压力测试发现有一张业务表在Transations较大的时候,会出现’enq: TX �C index contention’。由于该表主要是update操作,所以ORACLE ACS技术顾问针对该问题给出了2个建议,一个是重建该表的索引为10g支持的新特性索引:Hash-Partition Global Index;另一个就是调整该表的PCTFree,由10%调整为20%。
总结一下PCTFree的知识。
PCTFREE参数用来设置每个BLOCK中至少需要保留(reserve)多少可用空间(百分比值),为数据块中已有数据update操作时可能发生的数据量增长做准备。如下,PCTFREE=20时:
可以简单理解,PCTFREE是BLOCK块中为update操作的预留空间。如果pctfree设置为0,即不给block预留update操作的空间,则就有可能存在update操作没有分配到ITL接口,出现ITL Wait。我们可以结合initrans参数,模拟数据库出现ITL Wait的现象。
注:以下部分主要学习了piner的新作《构建ORACLE的高可用环境》,自己动手实验的。
步骤1,创建1个pctfree为0,initrans为1的测试用表。
Pctfree设置为0,则如果block在完全使用的情况下不会再有free space分配新的ITL。设置initrans为1,则block上默认分配的最小ITL数目为1(实际上block预留了最小2个ITL接口)。
SQL> create table test (a number) pctfree 0 initrans 1;
表已创建。
SQL>
SQL> select pct_free,ini_trans from user_tables where table_name = 'TEST';
PCT_FREE INI_TRANS
---------- ----------
0 1
SQL>
步骤2,test表插入数据,插满其中的block块。
SQL> begin
2 for i in 1..2000 loop
3 insert into test values(i) ;
4 end loop;
5 end;
6 /
PL/SQL过程已成功完成。
SQL> commit;
提交完成。
查看表test的block块的使用情况。可以看到,60707与60706已经完全插满所有行。
SQL> select f,b,count(*) from (
2 select dbms_rowid.rowid_relative_fno(rowid) f,
3 dbms_rowid.rowid_block_number(rowid) b
4 from test) group by f,b;
F B COUNT(*)
---------- ---------- ----------
1 60707 734
1 60708 532
1 60706 734
SQL>
Dump出60707block块的trace文件
SQL> alter system dump datafile 1 block 60707;
系统已更改。
步骤3,在已经完全使用的block上执行update操作。
根据预期,没有预留空间的情况下,新的session在不能分配到ITL接口的情况下会出现ITL等待。我们在已经完全使用的block.60707上分别打开3个不同的Session,对不同的rowid进行update操作,如下:
Session1:
SQL> update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=60707
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=1;
已更新1行。
SQL>
Session2:
SQL> update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=60707
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=2;
已更新1行。
SQL>
Session3:实际的测试中,session出现等待,无法返回结果。
SQL> update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=60707
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;
步骤4,确认数据库存在ITL等待事件如下,
SQL> select sid, EVENT from v$session_wait where sid='142';
SID EVENT
---------- ----------------------------------------------------------------
142 enq: TX - allocate ITL entry
查看数据库当前的sql,确实为session3的sql,如下:
SQL> SELECT username, sql_text from v$session a, v$sqltext b
2 where a.sql_address =b.address and a.username= 'SYS' and a.sid= '142' order by address, piece;
USERNAME SQL_TEXT
---------- ----------------------------------------------------------------
SYS update test set a=a where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=6
SYS 0707 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3
SQL>
上面试模拟产生ITL等待的场景,主要是为了自己学习验证pctfree的功能,实际上在大量并发下也会产生row lock,即ITL死锁。