[English]
作者:
fuyuncat
来源:
www.HelloDBA.com
我们知道,在表的数据块中,当数据插入时,要保证数据块上剩余空间大于、等于PCTFREE的比例设置,以用于数据更新和多事务处理,从而减少数据迁移(Row Migration)的发生;而当分配新的数据块时,会根据INITRANS的设置预留相应的ITL slot,保证并发事务能分配到ITL slot。
在索引中,这两个参数仅在有数据时创建或重建索引才会起作用,且仅在叶子节点上起作用。
INITRANS
INITRANS在索引数据块上是否起作用,是由索引在创建或重建时是否有数据(即是否会分配数据块)决定的。比较以下代码,第一段代码在truncate之后rebuild(即不会分配索引数据块),因而ITL slot数量为默认值2;第二段代码在有数据时rebuild,然后再truncate,此时再插入数据产生的新的索引块上ITL slot数量就受到INITRANS的控制:
SQL代码
- --代码1:
- HELLODBA.COM> truncate table idx_split;
- Table truncated.
- HELLODBA.COM> alter index idx_split_idx rebuild initrans 3 pctfree 10;
- Index altered.
- HELLODBA.COM> begin
- 2 for i in 1..35
- 3 loop
- 4 insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);
- 5 end loop;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- HELLODBA.COM> commit;
- Commit complete.
- HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';
- Session altered.
- --代码2:
- HELLODBA.COM> truncate table idx_split;
- Table truncated.
- HELLODBA.COM> insert into idx_split (a, b, c) values (1*3, lpad('A', 100, 'A'), sysdate);
- 1 row created.
- HELLODBA.COM> commit;
- Commit complete.
- HELLODBA.COM> alter index idx_split_idx rebuild initrans 3 pctfree 10;
- Index altered.
- HELLODBA.COM> truncate table idx_split;
- Table truncated.
- HELLODBA.COM> begin
- 2 for i in 1..35
- 3 loop
- 4 insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);
- 5 end loop;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';
- Session altered.
需要注意的是,当数据块上ITL Slot数量大于起作用的INITRANS时,在分裂时被“继承”。在以下例子中,在rebuild时,指定了INITRANS为3:
SQL代码
- HELLODBA.COM> truncate table idx_split;
- Table truncated.
- HELLODBA.COM> conn demo/demo
- Connected.
- HELLODBA.COM> alter session set events '10224 trace name context forever,level 1';
- Session altered.
- HELLODBA.COM> begin
- 2 for i in 1..100
- 3 loop
- 4 insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);
- 5 end loop;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- HELLODBA.COM> commit;
- Commit complete.
- HELLODBA.COM> alter index idx_split_idx rebuild initrans 3 pctfree 60;
- Index altered.
- HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';
- Session altered.
我们同时启动4个事务作用在最后一个节点,导致该数据块上分配5个(加一个递归事务ITL slot)ITL slot:
SQL代码
- -- Trans 1
- HELLODBA.COM> delete from idx_split where a=100*3;
- 1 row deleted.
- -- Trans 2
- HELLODBA.COM> delete from idx_split where a=99*3;
- 1 row deleted.
- --Trans 3
- HELLODBA.COM> delete from idx_split where a=98*3;
- 1 row deleted.
- --Trans 4
- HELLODBA.COM> delete from idx_split where a=97*3;
- 1 row deleted.
然后将它们全部提交或回滚,再插入数据,造成分裂:
SQL代码
- --9-1分裂
- HELLODBA.COM> begin
- 2 for i in 101..150
- 3 loop
- 4 insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);
- 5 end loop;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';
- Session altered.
- --5-5分裂
- HELLODBA.COM> insert into idx_split (a, b, c) values (138*3, lpad('A', 100, 'A'), sysdate);
- 1 row created.
- HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';
- Session altered.
Dump出分裂的数据块,可以看到所有数据块都被分配了5个ITL slot,而不是INITRANS(3)的数量:
SQL代码
- Block header dump: 0x03c0041d
- Object id on Block? Y
- seg/obj: 0x30a50 csc: 0x00.b1859616 itc: 5 flg: E typ: 2 - INDEX
- brn: 0 bdba: 0x3c00402 ver: 0x01 opc: 0
- inc: 0 exflg: 0
- Itl Xid Uba Flag Lck Scn/Fsc
- 0x01 0x005f.016.00000256 0x008019b5.0120.02 -B-- 1 fsc 0x0000.00000000
- 0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
- 0x03 0x005f.005.00000257 0x008019b4.0120.27 ---- 5 fsc 0x0000.00000000
- 0x04 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
- 0x05 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
PCTFREE
PCTFREE在分裂时则被忽略。在上述例子中,我们找到一块发生9-1分裂产生的数据块,可以看到其空闲空间为44b,空闲率为44/2048=2.1%,远远小于我们rebuild时的设定值(60)。
SQL代码
- ...
- kdxcofbo 66=0x42
- kdxcofeo 110=0x6e
- kdxcoavs 44
- ...
我们再插入一些中间数据,造成5-5分裂:
SQL代码
- HELLODBA.COM> begin
- 2 for i in 1..15
- 3 loop
- 4 insert into idx_split (a, b, c) values (50*3, lpad('A', 100, 'A'), sysdate);
- 5 end loop;
- 6 end;
- 7 /
- PL/SQL procedure successfully completed.
- HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';
- Session altered.
可以看到,发生分裂的数据块的空闲率为556/2048=27.1%,可见PCTFREE(60)也被忽略了。
SQL代码
- ...
- kdxcofbo 58=0x3a
- kdxcofeo 614=0x266
- kdxcoavs 556
- ...
--- Fuyuncat TBC ---