今天跟研发的同学讨论到了这个问题,index block split过程中涉及到的重新排序问题.
SQL> create table idx_split (a number, b varchar2(1446), c date); Table created SQL> create index idx_split_idx on idx_split (a, b) tablespace idx_2k pctfree 10; Index created begin for i in 1..1000 loop insert into tx_index_contention (a, b, c) values (i, lpad('A', 10, 'A'), sysdate); end loop; end; / PL/SQL procedure successfully completed SQL> commit; Commit complete SQL> SELECT height,blocks,lf_blks,br_blks,btree_space,used_space FROM INDEX_STATS WHERE NAME='IDX_SPLIT_IDX'; HEIGHT BLOCKS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ---------- ----------- ---------- 1 8 1 0 7996 2500 SQL> ANALYZE INDEX idx_split_idx VALIDATE STRUCTURE; Index analyzed SQL> SELECT height,blocks,lf_blks,br_blks,btree_space,used_space FROM INDEX_STATS WHERE NAME='IDX_SPLIT_IDX'; HEIGHT BLOCKS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ------------------- ---------- 2 8 4 1 40012 25924 SQL> select extent_id,file_id,block_id,blocks from dba_extents where segment_name='IDX_SPLIT_IDX' AND OWNER='SYS'; EXTENT_ID FILE_ID BLOCK_ID BLOCKS ---------- ---------- ---------- ---------- 0 6 128 8
插入1000条数据,leaf blocks=4 branch block=1
SQL> alter session set events '10224 trace name context forever,level 1'; Session altered SQL> SELECT height,blocks,lf_blks,br_blks,btree_space,used_space FROM INDEX_STATS WHERE NAME='IDX_SPLIT_IDX' ; HEIGHT BLOCKS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ---------- ----------- ---------- 2 8 4 1 40012 25924 SQL> insert into idx_split (a, b, c) values (1, lpad('A', 10, 'A'), sysdate); 1 row inserted SQL> commit; Commit complete SQL> SQL> select sysdate from dual; SYSDATE ----------- 2012/12/12
------------------------------------------------------------ *** 2012-12-12 13:44:52.311 *** SESSION ID:(668.2355) 2012-12-12 13:44:52.311 *** CLIENT ID:() 2012-12-12 13:44:52.311 *** SERVICE NAME:(yhdtest) 2012-12-12 13:44:52.311 *** MODULE NAME:(PL/SQL Developer) 2012-12-12 13:44:52.311 *** ACTION NAME:(Command Window - New) 2012-12-12 13:44:52.311 splitting leaf,dba 0x01800087,time 13:44:52.310 kdisnew_bseg_srch_cbk reject block -mark full,dba 0x01800086,time 13:44:52.311 kdisnew_bseg_srch_cbk rejecting block ,dba 0x01800086,time 13:44:52.311 kdisnew_bseg_srch_cbk reject block -mark full,dba 0x01800085,time 13:44:52.311 kdisnew_bseg_srch_cbk rejecting block ,dba 0x01800085,time 13:44:52.311 kdisnew_bseg_srch_cbk using block,dba 0x0180008f,time 13:44:52.313 ---------------------------------------------------------------
leaf,dba 0x01800087 发生了分裂 (第一个leaf block)
dump 第一个branch block
SQL> alter system dump datafile 6 block 131; System altered ---------------------------------------------------------------- Block header dump: 0x01800083 Object id on Block? Y seg/obj: 0x12ef4 csc: 0x00.17756d itc: 1 flg: E typ: 2 - INDEX brn: 0 bdba: 0x1800080 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0009.01d.00000389 0x00c003a5.00a7.02 C--- 0 scn 0x0000.0017756d Branch block dump ================= header address 140678466630220=0x7ff24207f24c kdxcolev 1 KDXCOLEV Flags = - - - kdxcolok 0 kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y kdxconco 3 kdxcosdc 1 kdxconro 3 kdxcofbo 34=0x22 kdxcofeo 8029=0x1f5d kdxcoavs 7995 kdxbrlmc 25165959=0x1800087 -----第一个leaf block kdxbrsno 2 kdxbrbksz 8056 kdxbr2urrc 0 row#0[8047] dba: 25165956=0x1800084 -----第二个 col 0; len 3; (3): c2 04 0d col 1; TERM row#1[8038] dba: 25165957=0x1800085 ..3 col 0; len 3; (3): c2 07 14 col 1; TERM row#2[8029] dba: 25165958=0x1800086 ..4 col 0; len 3; (3): c2 0a 1b col 1; TERM ----- end of branch block dump ----- End dump data blocks tsn: 7 file#: 6 minblk 131 maxblk 131 -------------------------------------------------------------------
SQL> variable file# number variable block# number execute :file#:=dbms_utility.data_block_address_file(to_number('1800087','xxxxxxx')); execute :block#:=dbms_utility.data_block_address_block(to_number('1800087','xxxxxxx'));SQL> SQL> PL/SQL procedure successfully completed. PL/SQL procedure successfully completed. SQL> SQL> SQL> SQL> print file#; FILE# ---------- 6 SQL> print block#; BLOCK# ---------- 135 SQL> alter system dump datafile 6 block 135; System altered SQL> alter system dump datafile 6 block 132; System altered SQL> select display_raw('c2040d','NUMBER') from dual; DISPLAY_RAW('C2040D','NUMBER') ---------------------------------------------------------------------------------------------------- 312
第二个leaf block 的min value = 312
Block header dump: 0x01800084 Object id on Block? Y seg/obj: 0x12ef4 csc: 0x00.177610 itc: 2 flg: E typ: 2 - INDEX brn: 0 bdba: 0x1800080 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0009.01e.00000389 0x00c003a7.00a7.02 --U- 1 fsc 0x0000.00177611 0x02 0x000a.006.00000756 0x00c00768.0172.19 C--- 0 scn 0x0000.00177571 Leaf block dump =============== header address 140678466630244=0x7ff24207f264 kdxcolev 0 KDXCOLEV Flags = - - - kdxcolok 1 kdxcoopc 0x89: opcode=9: iot flags=--- is converted=Y kdxconco 3 kdxcosdc 2 kdxconro 307 kdxcofbo 650=0x28a kdxcofeo 667=0x29b kdxcoavs 17 kdxlespl 0 kdxlende 0 kdxlenxt 25165957=0x1800085 kdxleprv 25165967=0x180008f kdxledsz 0 kdxlebksz 8032 row#0[667] flag: ------, lock: 0, len=24 col 0; len 3; (3): c2 04 0d ------------>312 col 1; len 10; (10): 41 41 41 41 41 41 41 41 41 41 col 2; len 6; (6): 00 41 74 8a 00 30 row#1[691] flag: ------, lock: 0, len=24 .....
第一个leaf block 的range <312
Block header dump: 0x01800087 Object id on Block? Y seg/obj: 0x12ef4 csc: 0x00.177576 itc: 2 flg: E typ: 2 – INDEX brn: 0 bdba: 0x1800080 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0009.01e.00000389 0x00c003a6.00a7.01 -B– 1 fsc 0x0000.00000000 0x02 0x000a.010.00000758 0x00c00770.0172.28 –U- 1 fsc 0x0000.00177649 Leaf block dump =============== header address 140678466630244=0x7ff24207f264 kdxcolev 0 KDXCOLEV Flags = – – – kdxcolok 1 kdxcoopc 0x80: opcode=0: iot flags=— is converted=Y kdxconco 3 kdxcosdc 2 kdxconro 163 kdxcofbo 362=0x16a kdxcofeo 4221=0x107d kdxcoavs 3859 kdxlespl 0 kdxlende 0 kdxlenxt 25165967=0x180008f kdxleprv 0=0x0 kdxledsz 0 kdxlebksz 8032 row#0[4221] flag: ——, lock: 0, len=23 col 0; len 2; (2): c1 02 col 1; len 10; (10): 41 41 41 41 41 41 41 41 41 41 col 2; len 6; (6): 00 41 74 89 00 00 row#1[4244] flag: ——, lock: 2, len=23 col 0; len 2; (2): c1 02 col 1; len 10; (10): 41 41 41 41 41 41 41 41 41 41 ……
row#0,row#1 的偏移量发生了重组,[4221]->[4244] 按照len=23递增 即物理address 发生了排序
row#0,row#1 被reorder为1,1,2,x 而row#1对应的rowid为max block address
SQL> SELECT height,blocks,lf_blks,br_blks,btree_space,used_space FROM INDEX_STATS WHERE NAME='IDX_SPLIT_IDX'; HEIGHT BLOCKS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ---------- ----------- ---------- 2 8 4 1 40012 25924 SQL> ANALYZE INDEX idx_split_idx VALIDATE STRUCTURE; Index analyzed SQL> SQL> SELECT height,blocks,lf_blks,br_blks,btree_space,used_space FROM INDEX_STATS WHERE NAME='IDX_SPLIT_IDX' 2 ; HEIGHT BLOCKS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ---------- ----------- ---------- 2 16 5 1 48008 25960
leaf block 从4增加到5,第一个leaf block 发生了分裂,具体过程为:
1. Allocate new index block from index freelist
2. Redistribute block so the lower half (by volume) of index entries remain in current block and move the other half into the new block
3. Insert the new index entry into appropriate leaf block
4. Update the previously full block such that its “next leaf block pointer” (kdxlenxt) references the new block
5. Update the leaf block that was the right of the previously full block such that its “previous leaf block pointer”(kdxleprv) also points to the new block
6. Update the branch block that references the full block and add a new entry to point to the new leaf block (effectively the lowest value in the new leaf block)
7. –add this one , split leaf block will reorder by value this is a behavior like rebuild.