资源预览内容
第1页 / 共5页
第2页 / 共5页
第3页 / 共5页
第4页 / 共5页
第5页 / 共5页
亲,该文档总共5页全部预览完了,如果喜欢就下载吧!
资源描述
深入研究深入研究 ITL 阻塞与阻塞与 ITL 死锁死锁1、什么是、什么是 ITLITL(Interested Transaction List)是 Oracle 数据块内部的一个组成部分,用来记录该块所有发生的事务,一个 itl 可以看作是一个记录,在一个时间,可以记录一个事务(包括提交或者未提交事务) 。当然,如果这个事务已经提交,那么这个 itl 的位置就可以被反复使用了,因为 itl 类似记录,所以,有的时候也叫 itl 槽位。如果一个事务一直没有提交,那么,这个事务将一直占用一个 itl 槽位,itl 里面记录了事务信息,回滚段的入口,事务类型等等。如果这个事务已经提交,那么,itl 槽位中还保存的有这个事务提交时候的 SCN号。如 dump 一个块,就可以看到 itl 信息:Itl Xid Uba Flag Lck Scn/Fsc0x01 0x0006.002.0000158e 0x0080104d.00a1.6e -U- 734 fsc 0x0000.6c9deff00x02 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 等待的例子:Piner10gR2create table test(a int) pctfree 0 initrans 1;Table created.我们这里指定 pctfree 为 0,initrans 为 1,就是为了更观察到 itl 的真实等待情况,那么,现在,我们给这些块内插入数据,把块填满,让它不能有空间分配。Piner10gR2begin2 for i in 1.2000 loop3 insert into test values(i);4 end loop;5 end;6 /PL/SQL procedure successfully completed.Piner10gR2commit;Commit complete.我们再检查数据填充的情况:Piner10gR2select 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 7341 29691 7341 29692 532可以发现,这 2000 条数据分布在 3 个块内部,其中有 2 个块添满了,一个块是半满的。我们 dump 一个满的块,可以看到 itl 信息:Piner10gR2alter system dump datafile 1 block 29690;回到 os,在 udump 目录下,检查跟踪文件,可以看到如下的信息Itl Xid Uba Flag Lck Scn/Fsc0x01 0x0006.002.0000158e 0x0080104d.00a1.6e -U- 734 fsc 0x0000.6c9deff00x02 0x0000.000.00000000 0x00000000.0000.00 - 0 fsc 0x0000.00000000发现,采用如上参数创建的表,块内部默认有 2 个 itl 槽位,如果这里不指定 initrans 1,默认是有 3 个itl 槽位的。因为只有 2 个 ITL 槽位,我们可以用三个会话来模拟等待:会话 1,我们更新这个块内部的第一行:Piner10gR2update 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 行:Piner10gR2update 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),我们更新这个块内部的第三行,发现被阻塞:Piner10gR2update test set a=a 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;可以看到,会话被阻塞观察这个时候的等待事件,我们可以发现是 ITL 等待:Piner10gR2select EVENT from v$session_wait where sid=153EVENT-enq: TX - allocate ITL entry因为该块只有 2 个 itl 槽位,而现在发生了 3 个事务,而且,因为该块被数据添满,根本没有剩余的空间来分配新的 itl,所以发生了等待。如果我们这个实验发生在半满的块 29692 上面,就发现进程 3 不会被阻塞,因为这里有足够的空间可以分配新的 itl。3、ITL 死锁死锁那么,理解了 itl 的阻塞,我们也就可以分析 itl 的死锁了,因为有阻塞,一般就能发生死锁。还是以上的表,因为有 2 个 itl 槽位,我们需要拿 2 个满的数据块,4 个进程来模拟 itl 死锁:会话 1Piner10gR2update 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.会话 2Piner10gR2update 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.会话 3Piner10gR2update 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.会话 4Piner10gR2update 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 等待。Piner10gR2update test set a=a 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;发现被阻塞那我们在会话 3,更新块 1,当然,也不是同一行Piner10gR2update test set a=a 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=3;被阻塞注意,如果是 9i,在这里就报死锁了,在进程 1,我们可以看到Piner9iR2update 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,注意,我们也不是更新的同一行数据Piner10gR2update test set a=a 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29691 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=4;被阻塞还有最后一个进程,进程 4,我们也不更新同一行数据Piner10gR2update test set a=a 2 where dbms_rowid.ROWID_BLOCK_NUMBER(rowid)=29690 3 and dbms_rowid.ROWID_ROW_NUMBER(rowid)=4;虽然,以上的每个更新语句,更新的都不是同一个数据行,但是,的确,所有的进程都被阻塞住了,那么,死锁的条件也达到了,马上,我们可以看到,进程 1 出现提示,死锁:Piner10gR2update test set a=a 2 where dbms_rowid.ROWID_BLOCK
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号