一、数据块的插入时寻找可用块的规则总结:
高水位与低高水位:低高水位与高水位之间存在的数据块的状态可能是未格式化或格式的。低高水位以下的是格式化了的,可以被使用。
1.首先,插入一条数据,只会使用高水位以下的数据块。
高水点的位置:L1块所包含数据块的边界,要么是区的边界
2.第一次插入一行数据,格式化块数?
并没有一个一定的数值,从DUMP L1块中看,有格式化5个,32个64个等。
3.插入一行数据,如何通过L3-->L2-->L1--数据块,这个过程来确定插入哪个块?
在ASSM表空间下:一个行在不同会话上是被随机插入高水位以下的不同的块。
具体说明如下:
L3选择L2,不随机,根据L2 Hint for inserts: 0x01c00081 这一行,确定要选择的L2。
在L2中,根据PID进行HASH,得到一个随机值,根据此值选择L1.--但是这受高水位影响,如果高水位范围内只有一个区,事实上将只选择这一个区对应的L1。
在L1中,根据PID进行HASH,得到一个随机值,根据此值选择数据块。
--实验时要注意,在同一窗口下,sqlplus快速退出再登陆,使用的是同一SID,所以插入的行会在同一数据块。
4.多个会话各自插入一行数据,插入顺序?
假设每行插入的数据所需要空间都不超过一个数据块:
同一会话向一张表中插入数据,是有序的,并且是插入同一个数据块。
如果多个会话向一张表中插入数据,是无序的,并且每个会话插入的数据在不同的数据块。
也就是:多个会话的插入是无序的,同一会话下插入有先后顺序。读取数据时,默认按ROWID,升序读取。
构造此实验的语句与结果:
create table t1 (id number,name varchar2(10));
session1--
insert into t1 values(1,'a');
insert into t1 values(2,'a');
commit;
session2--
insert into t1 values(3,'a');
insert into t1 values(4,'a');
commit;
session3--
insert into t1 values(5,'a');
insert into t1 values(6,'a');
commit;
session1不退出--
insert into t1 values(7,'a');
insert into t1 values(8,'a');
commit;
select id,name,rowid from t1;
select rowid,id,name,dbms_rowid.rowid_relative_fno(rowid) file_id,
dbms_rowid.rowid_block_number(rowid) block_id,
dbms_rowid.rowid_row_number(rowid) row_id from t1;
SQL> select id,name,rowid from t1;
ID NAME ROWID
---------- ---------- ------------------
1 a AAADfoAAFAAAACFAAA
2 a AAADfoAAFAAAACFAAB
5 a AAADfoAAFAAAACFAAC
6 a AAADfoAAFAAAACFAAD
7 a AAADfoAAFAAAACFAAE
8 a AAADfoAAFAAAACFAAF
3 a AAADfoAAFAAAACHAAA
4 a AAADfoAAFAAAACHAAB
8 rows selected.
SQL> select rowid,id,name,dbms_rowid.rowid_relative_fno(rowid) file_id,
2 dbms_rowid.rowid_block_number(rowid) block_id,dbms_rowid.rowid_row_number(rowid) row_id from t1;
ROWID ID NAME FILE_ID BLOCK_ID ROW_ID
------------------ ---------- ---------- ---------- ---------- ----------
AAADfoAAFAAAACFAAA 1 a 5 133 0
AAADfoAAFAAAACFAAB 2 a 5 133 1
AAADfoAAFAAAACFAAC 5 a 5 133 2
AAADfoAAFAAAACFAAD 6 a 5 133 3
AAADfoAAFAAAACFAAE 7 a 5 133 4
AAADfoAAFAAAACFAAF 8 a 5 133 5
AAADfoAAFAAAACHAAA 3 a 5 135 0
AAADfoAAFAAAACHAAB 4 a 5 135 1
8 rows selected.
实验:同一会话插入两条语句,再开一新会话插入一条,通过DBMS_ROWID查看行所在的数据块,会发现同一会话下插入同一块,不同会话不插入同一块。太简单了,没巾出来。
二、高水位及putfree值设置不当引起的性能问题--热块导致buffer busy waits等待事件
插入一条数据,只会使用高水位以下的数据块会引起的buffer busy waits性能问题?
首先,高水点的位置:L1块所包含数据块的边界,要么是区的边界。
而一个L1或者一个区所包含的数据块的个数是有限的。比如8KB在BLOCK时,系统自动管理区大小时,前16个区只有8个数据块,1-64 M时区大小为1M,128个块。64M以后的区大小是8M,有1024个数据块。
在8M的区时,有1024个块可以用,去除存储元数据的库,假如有1000个块可用,此时就是能支持1000个并发插入操作,有更多并发操作的时候,就不可避免的要出现多个会话同时向同一个数据块进行操作,此时就出现了热块--等待事件buffer busy waits。
1000个并发其实已经很大了,多用在日志型应用中。
如果并发超过1000个,并且buffer busy waits出现很多,已经影响到系统性能,有一个不太完美的解决方法是:在业务高峰来临前,在表中大量插入一批数据,推高高水位的位置;然后再删除数据,此时高水位之前有更多的数据块可供插入,就可以支持更高的并发了。
引起buffer busy waits等待事件,还有一种可能就是不合理的PCTFREE值。
因为在ASSM中,在L1中用五种状态: 75-100% 50-75% 25-50% 0-25% FULL来表示数据块的空闲状态,如果设置的值靠近这个监界值,比如PUTFREE是20%或24%,此时可能对数据块中数据进行几行的插入、更新 或删除就会导致数据块状态的改变,而数据块状态的改变,L1块中也要发生相应的改变来记录数据块的状态。
因为一个L1块管理多个数据块(比如8M区8KB数据块时一个L1管理1024个数据块),如果一个L1管理的多个数据块都要同时更新块的空间状态,也会引起L1块的争用--热块--等待事件buffer busy waits。
这个也能实验,不过不太好实验,要用一行数据比较长,配合PCTFREE的值,做到删除一行和插入一行或几行,块状态就发生变化,此时DUMP L1块来验证。
ASSM缺点:
ASSM下数据和索引的顺序不一致,导致聚簇因子增大
三、实验:验证插入的行默认只能插入到高水位以下的数据块
思路:先建表,手动给表分配多个区。使用多个会话,每个会话插入一行数据,顺便验证数据块的插入顺序
#############################33
BYS@ bys3>create table test11(aa int ,bb varchar2(10));
Table created.
BYS@ bys3>insert into test11 values(99,'first');
1 row created.
BYS@ bys3>commit;
Commit complete.
BYS@ bys3>alter table test11 allocate extent(size 1m);
Table altered.
BYS@ bys3>alter system checkpoint;
System altered.
BYS@ bys3>select header_file,header_block from dba_segments where segment_name='TEST11' and owner='BYS';
HEADER_FILE HEADER_BLOCK
----------- ------------
4 170
#####################
DUMP段头:
Extent Control Header --高水位Highwater:: 0x010000b0,在176号块。也就是第一个区的最后一个块。
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 17 #blocks: 256
last map 0x00000000 #maps: 0 offset: 2716
Highwater:: 0x010000b0 ext#: 0 blk#: 8 ext size: 8
#blocks in seg. hdr's freelists: 0
#blocks below: 5
mapblk 0x00000000 offset: 0
Unlocked
--------------------------------------------------------
Low HighWater Mark : --低高水位此时和高水位的DBA是一个块。
Highwater:: 0x010000b0 ext#: 0 blk#: 8 ext size: 8
#blocks in seg. hdr's freelists: 0
#blocks below: 5
mapblk 0x00000000 offset: 0
Level 1 BMB for High HWM block: 0x010000a8
Level 1 BMB for Low HWM block: 0x010000a8
--------------------------------------------------------
Segment Type: 1 nl2: 1 blksz: 8192 fbsz: 0
L2 Array start offset: 0x00001434
First Level 3 BMB: 0x00000000
L2 Hint for inserts: 0x010000a9 ---L2的块是169号块
Last Level 1 BMB: 0x01000101
Last Level II BMB: 0x010000a9
Last Level III BMB: 0x00000000
Map Header:: next 0x00000000 #extents: 17 obj#: 22989 flag: 0x10000000
Inc # 0
Extent Map
-----------------------------------------------------------------
0x010000a8 length: 8 --第一个区的起始地址是0x010000a8,四号文件,168号块。
0x010000b0 length: 8
--第二个区的起始地址是0x010000b0,4号文件176号块,与高水位的对应
0x010000b8 length: 8
0x010000c0 length: 8
0x010000c8 length: 8
0x010000d0 length: 8
0x010000d8 length: 8
0x010000e0 length: 8
0x010000e8 length: 8
0x010000f0 length: 8
0x010001a8 length: 8
0x010001b0 length: 8
0x010001b8 length: 8
0x010001c0 length: 8
0x010001c8 length: 8
0x010001d0 length: 8
0x01000100 length: 128
Auxillary Map
--------------------------------------------------------
Extent 0
: L1 dba: 0x010000a8 Data dba: 0x010000ab ---这里从L1 DBA可以看到,这一个L1管理了0和1号区。
Extent 1 : L1 dba: 0x010000a8 Data dba: 0x010000b0
Extent 2 : L1 dba: 0x010000b8 Data dba: 0x010000b9
Extent 3 : L1 dba: 0x010000b8 Data dba: 0x010000c0
Extent 4 : L1 dba: 0x010000c8 Data dba: 0x010000c9
Extent 5 : L1 dba: 0x010000c8 Data dba: 0x010000d0
Extent 6 : L1 dba: 0x010000d8 Data dba: 0x010000d9
Extent 7 : L1 dba: 0x010000d8 Data dba: 0x010000e0
Extent 8 : L1 dba: 0x010000e8 Data dba: 0x010000e9
Extent 9 : L1 dba: 0x010000e8 Data dba: 0x010000f0
Extent 10 : L1 dba: 0x010001a8 Data dba: 0x010001a9
Extent 11 : L1 dba: 0x010001a8 Data dba: 0x010001b0
Extent 12 : L1 dba: 0x010001b8 Data dba: 0x010001b9
Extent 13 : L1 dba: 0x010001b8 Data dba: 0x010001c0
Extent 14 : L1 dba: 0x010001c8 Data dba: 0x010001c9
Extent 15 : L1 dba: 0x010001c8 Data dba: 0x010001d0
Extent 16 : L1 dba: 0x01000100 Data dba: 0x01000102
--------------------------------------------------------
Second Level Bitmap block DBAs
--------------------------------------------------------
DBA 1: 0x010000a9
##############################################
DUMP 第一个L1--也是高水位内的惟一一个L1
BYS@ bys3>alter system dump datafile 4 block 168;
System altered.
BYS@ bys3>select value from v$diag_info where name like 'De%';
VALUE
----------------------------------------------------------------------------------------------------
/u01/diag/rdbms/bys3/bys3/trace/bys3_ora_27244.trc
###############DUMP信息如下:
Dump of First Level Bitmap Block
--------------------------------
nbits : 4 nranges: 2 parent dba: 0x010000a9 poffset: 0
unformatted: 8 total: 16 first useful block: 3
owning instance : 1
instance ownership changed at 01/25/2014 22:21:43
Last successful Search 01/25/2014 22:21:43
Freeness Status: nf1 0 nf2 0 nf3 0 nf4 5
Extent Map Block Offset: 4294967295
First free datablock : 3
Bitmap block lock opcode 3
Locker xid: : 0x0003.006.00001365
Dealloc scn: 8820451.0
Flag: 0x00000001 (-/-/-/-/-/HWM)
Inc #: 0 Objd: 22989
HWM Flag: HWM Set
Highwater:: 0x010000b0 ext#: 0 blk#: 8 ext size: 8
#blocks in seg. hdr's freelists: 0
#blocks below: 5
mapblk 0x00000000 offset: 0
--------------------------------------------------------
DBA Ranges : ---从这里也能验证这个L1管理了两个区,与段头的 Auxillary Map可以对应。
--------------------------------------------------------
0x010000a8 Length: 8 Offset: 0
0x010000b0 Length: 8 Offset: 8
0:Metadata 1:Metadata 2:Metadata 3:75-100% free
4:75-100% free 5:75-100% free 6:75-100% free 7:75-100% free
8:unformatted 9:unformatted 10:unformatted 11:unformatted
12:unformatted 13:unformatted 14:unformatted 15:unformatted
从DUMP信息中可以看到,第一个L1的第一个块168号块,也是这个段的第一个块的地址。
0:Metadata 1:Metadata 2:Metadata这三个对应的是168号块L1,169号块L2,170号块是段头--第一个L3。
高水位是在176号块,也就是第二个区的第一个块,这里因为一个区只有8个块,一个L1管理了两个区。
插入一行数据,从以上DUMP信息中可以看到,只格式化了高水位下的这个区。区中有三个是存放ASSM的管理信息,所以事实上能用的块是55个块,也就是这次插入数据格式化了5个块。。
注:在其它实验中,插入一行数据格式的数据块个数是不固定的,有过16个,32个,64个等。
插入一行数据格式化的数据块数量应该是和区大小以及高水位位置有一定关系吧,总之格式化数据块是按批进行的,具体一批是多少不清楚哈哈。
#######################3
现在使用下面脚本同时启动30个会话进行插入数据操作,然后查看插入的ROWID信息:
结果是;从查询中可以看到,插入的数据块都在高水位176这个数据块之下,被随机插入到了各个块中。
[oracle@bys3 ~]$ cat insert.sql
sqlplus bys/bys <<EOF
insert into bys.test11 values($1,'hello');
commit;
exec dbms_lock.sleep(2000);
EOF
#######
./insert.sql 1 &
./insert.sql 2 &
./insert.sql 3 &
./insert.sql 4 &
./insert.sql 5 &
./insert.sql 6 &
./insert.sql 7 &
./insert.sql 8 &
./insert.sql 9 &
./insert.sql 10 &
./insert.sql 11 &
./insert.sql 12 &
./insert.sql 13 &
./insert.sql 14 &
./insert.sql 15 &
./insert.sql 16 &
./insert.sql 17 &
./insert.sql 18 &
./insert.sql 19 &
./insert.sql 20 &
./insert.sql 21 &
./insert.sql 22 &
./insert.sql 23 &
./insert.sql 24 &
./insert.sql 25 &
./insert.sql 26 &
./insert.sql 27 &
./insert.sql 28 &
./insert.sql 29 &
./insert.sql 30 &
####################插入完成后查询:
BYS@ bys3>select dbms_rowid.ROWID_RELATIVE_FNO(rowid) fno,dbms_rowid.rowid_block_number(rowid) block#,aa,bb from test11 order by block#;
FNO BLOCK# AA BB
---------- ---------- ---------- ----------
4 171 99 first
4 171 1 hello
4 171 1 hello
4 171 4 hello
4 171 14 hello
4 171 18 hello
4 171 21 hello
4 171 26 hello
4 172 1 hello
4 172 12 hello
4 172 11 hello
4 172 19 hello
4 172 24 hello
4 172 28 hello
4 173 8 hello
4 173 29 hello
4 173 25 hello
4 173 13 hello
4 173 15 hello
4 174 27 hello
4 174 16 hello
4 174 6 hello
4 174 7 hello
4 174 2 hello
4 175 9 hello
4 175 5 hello
4 175 17 hello
4 175 22 hello
4 175 23 hello
4 175 3 hello
从查询中可以看到,插入的数据块都在高水位176这个数据块之下,被随机插入到了各个块中。