ITL阻塞与ITL死锁

0    280    1

Tags:

👉 本文共约4168个字,系统预计阅读时间或需16分钟。

目录

    首先要说的是,这个问题当初我是真遇到过,然后,就有了汪海的这篇文章:

    itl deadlock:http://www.orawh.com/80.html

    但是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槽位最好不要马上被覆盖,因为一致性读可能会用到这个信息,一致性读的时候,可能需要从这里获得回滚段的入口,并从回滚段中获得一致性读。

    itl的个数,受参数initrans控制,最大的itl个数,受maxtrans控制,在一个块内部,默认分配了2个或3个itl的个数,如果这个块内还有空闲空间,那么Oracle是可以利用这些空闲空间并再分配itl的。如果没有了空闲空间,那么,这个块因为不能分配新的itl,所以就可能发生itl等待。

    如果在并发量特别大的系统中,最好分配足够的itl个数,其实它并浪费不了太多的空间,或者,设置足够的pctfree,保证itl能扩展,但是pctfree有可能是被行数据给消耗掉的,如update,所以,也有可能导致块内部的空间不够而导致itl等待。

    2、ITL等待

    我们看一个ITL等待的例子:

    1. Piner@10gR2>create table test(a int) pctfree 0 initrans 1;
    2. Table created.

    我们这里指定pctfree为0,initrans为1,就是为了更观察到itl的真实等待情况,那么,现在,我们个这些块内插入数据,把块填满,让它不能有空间分配。

    1. Piner@10gR2>begin
    2. 2 for i in 1..2000 loop
    3. 3 insert into test values(i);
    4. 4 end loop;
    5. 5 end;
    6. 6 /
    7. PL/SQL procedure successfully completed.
    8. Piner@10gR2>commit;
    9. Commit complete.

    我们再检查数据填充的情况:

    1. Piner@10gR2>select f,b,count(*) from (
    2. 2 select dbms_rowid.rowid_relative_fno(rowid) f,
    3. 3 dbms_rowid.rowid_block_number(rowid) b
    4. 4 from test) group by f,b;
    5. ​ F B COUNT(*)

    6. ​ 1 29690 734
    7. ​ 1 29691 734
    8. ​ 1 29692 532

    可以发现,这2000条数据分布在3个块内部,其中有2个块添满了,一个块是半满的。我们dump一个满的块,可以看到itl信息:

    1. Piner@10gR2>alter system dump datafile 1 block 29690;

    回到os,在udump目录下,检查跟踪文件,可以看到如下的信息

    发现,采用如上参数创建的表,块内部默认有2个itl槽位,如果这里不指定initrans 1,默认是有3个itl槽位的。

    因为只有2个ITL槽位,我们可以用三个会话来模拟等待:

    会话1,我们更新这个块内部的第一行:

    1. Piner@10gR2>update test set a=a
    2. 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
    3. 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=1;
    4. 1 row updated.

    会话2,我们更新这个块内部的第2行:

    1. Piner@10gR2>update test set a=a
    2. 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
    3. 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=2;
    4. 1 row updated.

    会话3(SID=153),我们更新这个块内部的第三行,发现被阻塞:

    1. Piner@10gR2>update test set a=a
    2. 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690
    3. 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;

    可以看到,会话被阻塞

    本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信dbaup66,谢谢!
    AiDBA后续精彩内容已被站长无情隐藏,请输入验证码解锁本文!
    验证码:
    获取验证码: 请先关注本站微信公众号,然后回复“验证码”,获取验证码。在微信里搜索“AiDBA”或者“dbaup6”或者微信扫描右侧二维码都可以关注本站微信公众号。

    标签:

    Avatar photo

    小麦苗

    学习或考证,均可联系麦老师,请加微信db_bao或QQ646634621

    您可能还喜欢...

    发表回复