但是NinGoo 在下面回复说,10g模拟不到这样的情况了,开始我没有太在意,后来再想想,9i这么做的确是不对的,因为还有其它的进程可以释放资源,根本还没有达到死锁的条件。那么,10g就没有itl死锁了吗?也不是的,10g也有,不过是改进了一下,需要把所有的进程阻塞住的时候,才能爆发出死锁。
从死锁的原理上来看,10g是正确的,9i是欠完善的。我们现在完整的分析一下itl等待,以及itl死锁的前因后果,因为这部分在我的新书中也有涉及,属于比较难的一部分,先透露出来,免得大家到时候看书可能看得比较糊涂。
1、什么是ITL
ITL(Interested Transaction List)是Oracle数据块内部的一个组成部分,用来记录该块所有发生的事务,一个itl可以看作是一个记录,在一个时间,可以记录一个事务(包括提交或者未提交事务)。当然,如果这个事务已经提交,那么这个itl的位置就可以被反复使用了,因为itl类似记录,所以,有的时候也叫itl槽位。
如果一个事务一直没有提交,那么,这个事务将一直占用一个itl槽位,itl里面记录了事务信息,回滚段的入口,事务类型等等。如果这个事务已经提交,那么,itl槽位中还保存的有这个事务提交时候的SCN号。如dump一个块,就可以看到itl信息:
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0006.002.0000158e 0x0080104d.00a1.6e --U- 734 fsc 0x0000.6c9deff0
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
对于已经提交的事务,itl槽位最好不要马上被覆盖,因为一致性读可能会用到这个信息,一致性读的时候,可能需要从这里获得回滚段的入口,并从回滚段中获得一致性读。
itl的个数,受参数initrans控制,最大的itl个数,受maxtrans控制,在一个块内部,默认分配了2个或3个itl的个数,如果这个块内还有空闲空间,那么Oracle是可以利用这些空闲空间并再分配itl的。如果没有了空闲空间,那么,这个块因为不能分配新的itl,所以就可能发生itl等待。
如果在并发量特别大的系统中,最好分配足够的itl个数,其实它并浪费不了太多的空间,或者,设置足够的pctfree,保证itl能扩展,但是pctfree有可能是被行数据给消耗掉的,如update,所以,也有可能导致块内部的空间不够而导致itl等待。
2、ITL等待
我们看一个ITL等待的例子:
Piner@10gR2>create table test(a int) pctfree 0 initrans 1;
Table created.
我们这里指定pctfree为0,initrans为1,就是为了更观察到itl的真实等待情况,那么,现在,我们个这些块内插入数据,把块填满,让它不能有空间分配。
Piner@10gR2>begin
2 for i in 1..2000 loop
3 insert into test values(i);
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
Piner@10gR2>commit;
Commit complete.
我们再检查数据填充的情况:
Piner@10gR2>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 29690 734
1 29691 734
1 29692 532
可以发现,这2000条数据分布在3个块内部,其中有2个块添满了,一个块是半满的。我们dump一个满的块,可以看到itl信息:
Piner@10gR2>alter system dump datafile 1 block 29690;
回到os,在udump目录下,检查跟踪文件,可以看到如下的信息
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0006.002.0000158e 0x0080104d.00a1.6e --U- 734 fsc 0x0000.6c9deff0
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
发现,采用如上参数创建的表,块内部默认有2个itl槽位,如果这里不指定initrans 1,默认是有3个itl槽位的。
因为只有2个ITL槽位,我们可以用三个会话来模拟等待:
会话1,我们更新这个块内部的第一行:
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=1;
1 row updated.
会话2,我们更新这个块内部的第2行:
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=2;
1 row updated.
会话3(SID=153),我们更新这个块内部的第三行,发现被阻塞:
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;
可以看到,会话被阻塞
观察这个时候的等待事件,我们可以发现是ITL等待:
Piner@10gR2>select EVENT from v$session_wait where sid=153
EVENT
----------------------------
enq: TX - allocate ITL entry
因为该块只有2个itl槽位,而现在发生了3个事务,而且,因为该块被数据添满,根本没有剩余的空间来分配新的itl,所以发生了等待。如果我们这个实验发生在半满的块29692上面,就发现进程3不会被阻塞,因为这里有足够的空间可以分配新的itl。
3、ITL死锁
那么,理解了itl的阻塞,我们也就可以分析itl的死锁了,因为有阻塞,一般就能发生死锁。还是以上的表,因为有2个itl槽位,我们需要拿2个满的数据块,4个进程来模拟itl死锁:
会话1
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=1;
1 row updated.
会话2
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=2;
1 row updated.
会话3
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=1;
1 row updated.
会话4
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=2;
1 row updated.
以上4个进程把2个不同块的4个itl槽位给消耗光了,现在的情况,就是让他们互相锁住,达成死锁条件,回到会话1,更新块2,注意,以上4个操作,包括以下的操作,更新的根本不是同一行数据,主要是为了防止出现的是TX等待。
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;
发现被阻塞
那我们在会话3,更新块1,当然,也不是同一行
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;
被阻塞
注意,如果是9i,在这里就报死锁了,在进程1,我们可以看到
Piner@9iR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;
update test set a=a
where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
但是,在10g里面,这个时候,死锁是不会发生的,因为这里的进程1还可以等待进程4释放资源,进程3还可以等待进程2释放资源,只要进程2与进程4释放了资源,整个环境又活了,那么我们需要把这两个进程也塞住。
会话2,注意,我们也不是更新的同一行数据
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=4;
被阻塞
还有最后一个进程,进程4,我们也不更新同一行数据
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=4;
虽然,以上的每个更新语句,更新的都不是同一个数据行,但是,的确,所有的进程都被阻塞住了,那么,死锁的条件也达到了,马上,我们可以看到,进程1出现提示,死锁:
Piner@10gR2>update test set a=a
2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;
update test set a=a
where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691
and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
4、ITL等待与死锁的避免
为了避免以上的情况发生,我们一定要注意在高并发环境下的表中,正确的设置itl个数,如4个,8个等等,保证该块有足够的itl槽位,保证事务能顺利的进行,而没有itl的等待。关于itl的等待,在statspack的段报告中,也能很明显的看到:
Top 5 ITL Waits per Segment for DB: TEST Instance: test Snaps: 13013 -13014
-> End Segment ITL Waits Threshold: 100
Subobject Obj. ITL
Owner Tablespace Object Name Name Type Waits %Total
---------- ---------- -------------------- ---------- ----- ------------ -------
TEST TBS_EL_IND IDX_LLORDER_ORDERID INDEX 3 75.00
TEST TBS_INDEX2 IDX_AUC_FEED_FDATE INDEX 1 25.00
如果出现的频率很小,象上面的情况,一般可以不用干预,但是,如果waits很多,则表示这个对象有很严重的itl争用情况,需要增加itl个数。
另外注意的是,有itl等待,并不意味会发生itl死锁,从上面的例子可以看到,发生itl死锁的条件还是瞒苛刻的,如果发生了itl死锁,只能证明,你的系统中,itl等待已经非常严重了。
如果想增加initrans个数,参数可以动态修改,但是,只是针对以后的新块起效,以前的块如果想生效,需要在新参数下,重整表数据,如重建该表,或者move该表。
分享到:
相关推荐
BLOG_【故障处理】Oracle_lhr_队列等待之TX - allocate ITL entry案例.pdfBLOG_【故障处理】Oracle_lhr_队列等待之TX - allocate ITL entry案例.pdf
队列等待之TX - allocate ITL entry引起的死锁处理 Buffer busy waits异常等待事件分析与处理。 Buffer latch异常等待事件分析与处理。 Db file parallel read异常等待事件分析与处理。 Db file sequential read异常...
ITL(Interested Transaction List)是Oracle数据块内部的一个组成部分,用来记录该块所有发生的事务,一个itl可以看作是一个记录,在一个时间,可以记录一个事务(包括提交或者未提交事务)。当然,如果这个事务已经...
Bug 9865890 ITL WASTING A LOT OF SPACE IN INDEXES
ITL端口 ITL的端口
springboot-postgres-kafka:kafka ITL Hadoop
Oracle中关于事务槽(ITL)
findp_txITL_beta_cell tx-ITL系统仿真通过输入SNR Nc 等数值进行仿真计算
安装ITL EEPROM Downloader 1.0.4软件,安装完成以后查看电脑开始目录看看是否有这个软件,没有的话到安装目录 C:\Program Files (x86)\ITL EEPROM Downloader去打开这个EEPROM Downloader软件2....
cobit itsm book. This book describes good it managemant implementation. Good for it profwssionals
主要针对oracle事务槽讲解。一本很经典的电子书。分享给大家
不错的参考资料哦!
itlApp:ITL移动应用程序的API代码源
现网上的ITL9341_51单片机的驱动程序很少,特上传分享。
ANSI/NIST-ITL 1-2000 是美国国家信息系统标准定义的指纹、面部、疤痕和纹身 (SMT) 信息交换的数据格式。 NIST 文件的优点是能够在一个文件中包含有关该人的多个图像和其他类型的数据,这简化了参与方之间的生物...
itl-ae, 信息理论学习自动编码器 使用活页夹在线测试这里代码。国际交易日志信息理论自动编码器,Eder,Matthew Emigh,C 。 IJCNN 2016 ( 接受)安装安装Anaconda环境( 推荐推荐) 。在该环境中,更新 Theano: c
英国ITL纸币器,由于其自身的DLL功能太弱,所以做了二次封装,可供C#使用。
1.8寸ST7735 ITL9163B TFT 8位并口驱动keil项目; STM32F103R8 MCU //======液晶屏数据线接线==========// //本模块默认数据总线类型为8位并行模式 //8位模式接线:8位模式模块接低8位总线,即: //液晶屏LCD_D0对应...
ITL Web安全阻止所有主要Web浏览器上的所有恶意网站,危险的下载和讨厌的广告。 ITL Web Safe是所有主要Web浏览器的新一代浏览器扩展名。 ITL Web安全在互联网上冲浪时阻止所有危险的网站和恶意软件感染。它可以...
信息理论学习的权威著作This book presents the first cohesive treatment of Information Theoretic Learning (ITL) algorithms to adapt linear or nonlinear learning machines both in supervised or ...