Oracle Block浅析2:ITL(Interested Transaction List)
一.ITL(Interested Transaction List):
ITL(Interested Transaction List)是Oracle數(shù)據(jù)塊內(nèi)部的一個(gè)組成部分,位于數(shù)據(jù)塊頭(block header),itl由xid,uba,flag,lck和scn/fsc組成,
用來記錄該塊所有發(fā)生的事務(wù),一個(gè)itl可以看作是一條事務(wù)記錄
當(dāng)發(fā)出一條sql語句時(shí),ORACLE會(huì)記錄下這個(gè)時(shí)刻(SCN),然后在buffer cache中查找需要的BLOCK,或者從磁盤上讀。當(dāng)別的會(huì)話修改了數(shù)據(jù),或者正在修改數(shù)據(jù),就會(huì)在相應(yīng)的block上記錄ITL,此時(shí)ORACLE發(fā)現(xiàn)ITL中記錄的SCN(Scn/Fsc)大于SELECT時(shí)刻的SCN,那么ORACLE就會(huì)根據(jù)ITL中的Uba找到UNDO信息獲得該block的前鏡像,然后在buffer cache 中構(gòu)造出CR(consistent read)塊,此時(shí)ORALCE 也會(huì)檢查構(gòu)造出來的BLOCK中ITL記錄的SCN(Scn/Fsc),如果SCN(Scn/Fsc)還大于select時(shí)刻的SCN,那么一直重復(fù)構(gòu)造前鏡像,然后ORACLE找到前鏡像BLOCK中的ITL的SCN是否小于select的SCN,同時(shí)檢查這個(gè)事物有沒有提交或者回滾,如果沒有,那么繼續(xù)構(gòu)造前鏡像,直到找到需要的BLOCK,如果在構(gòu)造前鏡像的過程中所需的UNDO信息被覆蓋了,就會(huì)報(bào)快照過舊的錯(cuò)誤。
二.ITL Cleanout和Delayed block cleanout.
在接觸ITL Cleanout和Delayed block cleanout之前先了解一個(gè)概念--快速提交:在事務(wù)提交(commit)前,會(huì)在數(shù)據(jù)塊的頭部記錄下這個(gè)Cleanout SCN(Csc)號(hào)、Undo Block Address(Uba)和Transaction ID(Xid);并且在在對(duì)應(yīng)Interested Transaction List(Itl)中設(shè)置鎖標(biāo)志,記錄這個(gè)事務(wù)在這數(shù)據(jù)塊中產(chǎn)生的鎖的數(shù)目;同時(shí)在對(duì)應(yīng)修改的數(shù)據(jù)記錄上打上行級(jí)鎖標(biāo)志,并映射到對(duì)應(yīng)的Itl去。當(dāng)提交時(shí),并不會(huì)一一清除掉所有鎖標(biāo)志,而是給對(duì)應(yīng)的Itl打上相應(yīng)標(biāo)志,告訴后面訪問該數(shù)據(jù)塊的事務(wù),相應(yīng)的事務(wù)已經(jīng)提交。這就叫做快速提交(Fast Commit)。
2.1導(dǎo)出block信息:
1 SQL> select * from t; 2 3 ID NAME 4 ---------- ------------------------------ 5 1 oracle 6 2 oracle 7 3 noslq 8 SQL> update t set name='mysql' where id=2; 9 10 1 row updated. 11 12 SQL> select 13 2 dbms_rowid.rowid_relative_fno(rowid) REL_FNO, 14 3 dbms_rowid.rowid_block_number(rowid) BLOCK_NO 15 4 from t; 16 17 REL_FNO BLOCK_NO 18 ---------- ---------- 19 1 61186 20 1 61186 21 1 61186 22 23 SQL> alter system dump datafile 1 block 61186; 24 25 System altered. 26 27 SQL> oradebug setmypid; 28 Statement processed. 29 SQL> oradebug tracefile_name 30 /u01/admin/sun/udump/sun_ora_1832.trc 31 SQL> !vi /u01/admin/sun/udump/sun_ora_1832.trc
2.2查看trace文件(commit前):
1 -------------------- 2 3 Itl Xid Uba Flag Lck Scn/Fsc 4 0x01 0x0001.026.00000150 0x008003c0.0113.17 ---- 1 fsc 0x0000.00000000 5 0x02 0x0005.013.00000190 0x0080004b.013a.17 ---- 1 fsc 0x0001.00000000 6 -------------------- 7 block_row_dump: 8 tab 0, row 0, @0x1f6e 9 tl: 13 fb: --H-FL-- lb: 0x0 cc: 2 10 col 0: [ 2] c1 02 11 col 1: [ 6] 6f 72 61 63 6c 65 12 tab 0, row 1, @0x1f55 13 tl: 12 fb: --H-FL-- lb: 0x2 cc: 2 --對(duì)應(yīng)itl 0x02 14 col 0: [ 2] c1 03 15 col 1: [ 5] 6d 79 73 71 6c 16 tab 0, row 2, @0x1f61 17 tl: 13 fb: --H-FL-- lb: 0x1 cc: 2 18 col 0: [ 2] c1 04 19 col 1: [ 6] 6f 72 61 63 6c 65 20 end_of_block_dump
2.3?查看trace文件(commit后):即產(chǎn)生快速提交
1 ---------------- 2 Start dump data blocks tsn: 0 file#: 1 minblk 61186 maxblk 61186 3 buffer tsn: 0 rdba: 0x0040ef02 (1/61186) 4 scn: 0x0000.000d206f seq: 0x01 flg: 0x02 tail: 0x206f0601 5 frmt: 0x02 chkval: 0x0000 type: 0x06=trans data 6 ---------------- 7 Itl Xid Uba Flag Lck Scn/Fsc 8 0x01 0x0001.026.00000150 0x008003c0.0113.17 ---- 1 fsc 0x0000.00000000 9 0x02 0x0005.013.00000190 0x0080004b.013a.17 --U- 1 fsc 0x0001.000d206f 10 11 ----------------- 12 block_row_dump: 13 tab 0, row 0, @0x1f6e 14 tl: 13 fb: --H-FL-- lb: 0x0 cc: 2 15 col 0: [ 2] c1 02 16 col 1: [ 6] 6f 72 61 63 6c 65 17 tab 0, row 1, @0x1f55 18 tl: 12 fb: --H-FL-- lb: 0x2 cc: 2 --對(duì)應(yīng)itl 0x02 19 col 0: [ 2] c1 03 20 col 1: [ 5] 6d 79 73 71 6c 21 tab 0, row 2, @0x1f61 22 tl: 13 fb: --H-FL-- lb: 0x1 cc: 2 23 col 0: [ 2] c1 04 24 col 1: [ 6] 6f 72 61 63 6c 65 25 end_of_block_dump
對(duì)比兩次ITL(快速提交前后)信息發(fā)現(xiàn):ITL為0x02的 Flag由‘----’變成‘--U-',即事物有活動(dòng)變?yōu)橐烟峤?Scn/Fsc也發(fā)生了變化) 。但我們可以看到Lck還是1,也就是說行上的鎖還未釋放。--U-什么時(shí)候會(huì)變成C---呢?只有當(dāng)oracle在該塊上發(fā)生了itl cleanout或者delayed block cleanout時(shí)才會(huì)將之變成C---。
什么是itl cleanout:
一個(gè)新的事務(wù)過來時(shí),它首先會(huì)選擇一個(gè)itl槽,首先oracle采用C---狀態(tài)的事務(wù),如果沒有C---狀態(tài)的事務(wù),oracle就會(huì)發(fā)生一次itl cleanout,檢查所有的ITL相關(guān)的事務(wù),如果確認(rèn)事務(wù)已經(jīng)提交了,就將之修改為C---狀態(tài)了。
此時(shí)再來一個(gè)事務(wù)后,可以發(fā)現(xiàn)其狀態(tài)變?yōu)?#xff1a;
1 Itl Xid Uba Flag Lck Scn/Fsc 2 0x01 0x0001.026.00000150 0x008003c0.0113.17 ---- 1 fsc 0x0000.00000000 3 0x02 0x0005.013.00000190 0x0080004b.013a.17 C--- 0 scn 0x0000.000d206f
delayed block cleant有兩種情況下會(huì)發(fā)生:
1.如果一個(gè)transaction修改的block超過db cache的10%.
2.當(dāng)一個(gè)事務(wù)未提交時(shí),其修改過的block就已經(jīng)寫到硬盤上去了。此時(shí)事務(wù)提交了,并不會(huì)修改數(shù)據(jù)塊上的狀態(tài)。
導(dǎo)出block信息:
1 SQL> select * from t; 2 3 ID NAME 4 ---------- ------------------------------ 5 1 oracle 6 2 mysql 7 3 noslq 8 9 SQL> update t set name='informax' where id=1; 10 11 1 row updated. 12 13 SQL> select 14 2 dbms_rowid.rowid_relative_fno(rowid) REL_FNO, 15 3 dbms_rowid.rowid_block_number(rowid) BLOCK_NO 16 4 from t; 17 18 REL_FNO BLOCK_NO 19 ---------- ---------- 20 1 61186 21 1 61186 22 1 61186 23 24 SQL>
25 26 --27 28 SQL> alter system flush buffer_cache; --在未提交的情況下,將數(shù)據(jù)寫如此盤 29 30 System altered. 31 32 SQL>
--查看trace文件(commit前)
1 Start dump data blocks tsn: 0 file#: 1 minblk 61186 maxblk 61186 2 buffer tsn: 0 rdba: 0x0040ef02 (1/61186) 3 scn: 0x0000.000d32c3 seq: 0x01 flg: 0x04 tail: 0x32c30601 4 frmt: 0x02 chkval: 0x05fb type: 0x06=trans data 5 6 Itl Xid Uba Flag Lck Scn/Fsc 7 0x01 0x0001.001.00000153 0x00800164.0118.19 ---- 1 fsc 0x0000.00000000 8 0x02 0x0005.013.00000190 0x0080004b.013a.17 C--- 0 scn 0x0000.000d206f
--提交
1 SQL>commit;--正常情況下,會(huì)修改block里的scn,但在此種情況下oracle并未修改,oracle只更新undo segment header slot。
--查看trace文件(commit后)
1 Start dump data blocks tsn: 0 file#: 1 minblk 61186 maxblk 61186 2 buffer tsn: 0 rdba: 0x0040ef02 (1/61186) 3 scn: 0x0000.000d32c3 seq: 0x01 flg: 0x04 tail: 0x32c30601 4 frmt: 0x02 chkval: 0x05fb type: 0x06=trans data 5 6 Itl Xid Uba Flag Lck Scn/Fsc 7 0x01 0x0001.001.00000153 0x00800164.0118.19 ---- 1 fsc 0x0000.00000000 8 0x02 0x0005.013.00000190 0x0080004b.013a.17 C--- 0 scn 0x0000.000d206f
在提交之前buffer cache中的臟數(shù)據(jù)已經(jīng)被DBwn進(jìn)程寫回,那么Itl中的事務(wù)標(biāo)志就不會(huì)被更新,并且數(shù)據(jù)塊的Itl列表也不會(huì)記錄下事務(wù)的Commit SCN 。后面的事務(wù)或查詢語句訪問該數(shù)據(jù)塊時(shí),為了檢測(cè)是否需要進(jìn)行一致性讀(如果數(shù)據(jù)塊的Itl中記錄的提交事務(wù)的Commit SCN 大于當(dāng)前訪問該數(shù)據(jù)塊的SCN,則需要進(jìn)行一致性讀),就需要通過Undo Block Address和Transaction ID到回滾段的事務(wù)信息表中去檢查前面事務(wù)的狀態(tài)和它的Commit SCN,確定是否做一致性讀,最后將前面事務(wù)在該數(shù)據(jù)塊上的標(biāo)志做一次Cleanout。
--查詢
1 SQL> select * from t; 2 3 ID NAME 4 ---------- ------------------------------ 5 1 informax 6 2 mysql 7 3 noslq 8 SQL>
--查看trace文件
1 Start dump data blocks tsn: 0 file#: 1 minblk 61186 maxblk 61186 2 buffer tsn: 0 rdba: 0x0040ef02 (1/61186) 3 scn: 0x0000.000d35df seq: 0x01 flg: 0x00 tail: 0x35df0601 4 frmt: 0x02 chkval: 0x0000 type: 0x06=trans data 5 6 Itl Xid Uba Flag Lck Scn/Fsc 7 0x01 0x0001.001.00000153 0x00800164.0118.19 C--- 0 scn 0x0000.000d3322 8 0x02 0x0005.013.00000190 0x0080004b.013a.17 C--- 0 scn 0x0000.000d206f
對(duì)比兩次ITL 0x01中的Flag,lck,Scn/Fsc的值,即可發(fā)現(xiàn)其變化
三.根據(jù)ITL找數(shù)據(jù)的前鏡像?
--前面提到了ITL 保存了SCN 和Unto的信息。 在這里,我們就測(cè)試一下通過ITL 找到對(duì)應(yīng)的Undo 內(nèi)容
3.1.1 準(zhǔn)備測(cè)試數(shù)據(jù)
1 --查看t表的記錄 2 SQL> select * from t; 3 4 ID NAME 5 ---------- ------------------------------ 6 1 oracle 7 2 oracle 8 3 noslq 9 10 SQL> 11 12 -- 查看id=1 記錄存儲(chǔ)的數(shù)據(jù)塊位置 13 SQL> select 14 2 dbms_rowid.rowid_relative_fno(rowid) file_id, 15 3 dbms_rowid.rowid_block_number(rowid) block_id 16 4 from t where id=3; 17 18 FILE_ID BLOCK_ID 19 ---------- ---------- 20 1 61186 21 22 SQL> 23 24 --更新id=1的數(shù)據(jù)庫(kù),不要提交。此時(shí)相應(yīng)的ITL中會(huì)產(chǎn)生一個(gè)SCN(Scn/Fsc) 25 SQL> update t set name='oracle' where id=3; 26 1 row updated. 27 SQL> 28 29 -- dump 該數(shù)據(jù)塊(新建會(huì)話) 30 SQL> alter system dump datafile 1 block 61186; 31 32 System altered. 33 34 SQL> 35 36 --使用oradebug 查看當(dāng)前trace 文件位置 37 SQL> oradebug setmypid; 38 Statement processed. 39 SQL> oradebug tracefile_name 40 /u01/admin/sun/udump/sun_ora_1764.trc 41 SQL> 42 43 --在trace 文件里找到我們的ITL: 44 45 Itl Xid Uba Flag Lck Scn/Fsc 46 0x01 0x0001.026.00000150 0x008003c0.0113.17 ---- 1 fsc 0x0000.00000000 47 0x02 0x0007.02c.00000141 0x0080006d.00de.01 C--- 0 scn 0x0000.000d1951 48 49 --因?yàn)槲覀儓?zhí)行了一條update 操作,并且沒有commit,那么這里的lock 為1,即Lck值為1. 即對(duì)應(yīng)我們ITL 值為0x01 的記錄。 50 51 52 SQL> select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn,ubarec from v$transaction; 53 54 XIDUSN XIDSLOT XIDSQN UBAFIL UBABLK UBASQN UBAREC 55 ---------- ---------- ---------- ---------- ---------- ---------- ---------- 56 1 38 336 2 960 275 23
3.1.2 驗(yàn)證XID
1 --ITL中的XID的格式為: usn#.slot#.wrap# 2 --ITL 為0x01中的XID=0x0001.026.00000150 3 4 SQL> select to_number('0001','XXXXX') from dual; 5 6 TO_NUMBER('0001','XXXXX') 7 ------------------------- 8 1 9 10 SQL> select to_number('026','XXXXX') from dual; 11 12 TO_NUMBER('026','XXXXX') 13 ------------------------ 14 38 15 16 SQL> select to_number('00000150','XXXXXXXXX')from dual; 17 18 TO_NUMBER('00000150','XXXXXXXXX') 19 --------------------------------- 20 336 21 22 這個(gè)和V$TRANSACTION中記錄的XIDUSN,XIDSLOT,XIDSQN相同。
3.1.3 驗(yàn)證uba
1 --UBA的格式為:DBA.seq#.rec# 2 --ITL為0x01記錄中的UBA=0x008003c0.0113.17, 其中0x008003c0表示的DBA(Data Block Address)的地址。 3 4 --將DBA(Data Block Address)解析成file_id 和 block_id. 5 SQL> select 6 2 dbms_utility.data_block_address_file(to_number('008003c0','xxxxxxxxxxxx')) file_id, 7 3 dbms_utility.data_block_address_block(to_number('008003c0','xxxxxxxxxxxx')) block_id 8 4 from dual; 9 10 FILE_ID BLOCK_ID 11 ---------- ---------- 12 2 960 13 14 --將seq#轉(zhuǎn)化成 UBASQN 15 SQL> select to_number('0113','xxxx') from dual; 16 17 TO_NUMBER('00DE','XXXX') 18 ------------------------ 19 275 20 21 --將rec#轉(zhuǎn)化成 UBAREC 22 SQL> select to_number('17','xxxx') from dual; 23 24 TO_NUMBER('17','XXXX') 25 ---------------------- 26 23 27 28 這個(gè)和v$transaction相同。
3.1.5 dump undo回滾段,找到更改的前鏡像
1 -- dump undo block 2 SQL> alter system dump datafile 2 block 960; 3 System altered. 4 5 --get trace file 6 SQL> oradebug setmypid 7 Statement processed. 8 SQL> oradebug tracefile_name 9 /u01/admin/sun/udump/sun_ora_1629.trc 10 SQL> 11 在dump 文件中找到xid 為 0x0001.026.00000150 的記錄。 12 --小技巧: 13 --這個(gè)文件很大,查找很麻煩,我們可以使用vi 的查找功能來實(shí)現(xiàn)。 14 -- (1)vi /opt/oracle/diag/rdbms/nwom/nwom/trace/nwom_ora_13900.trc 15 -- (2)輸入:/0x0001.026.00000150 16 -- (3)如果只有一條記錄,一次就能匹配到,如果有多條記錄,我們按字母n,查找下一條,知道找到結(jié)果位置。 17 -- 18 19 --查找的信息如下: 20 ******************************************************************************** 21 UNDO BLK: 22 xid: 0x0001.026.00000150 seq: 0x113 cnt: 0x17 irb: 0x17 icl: 0x0 flg: 0x0000 23 24 --該數(shù)據(jù)塊的uba=0x008003c0.0113.17。 25 --uba的格式:DBA.seq#.rec#。 26 --這個(gè)的cnt對(duì)應(yīng)uba中的rec#。根據(jù)這個(gè)cnt序列號(hào),我們查找對(duì)應(yīng)的具體內(nèi)容: 27 28 *----------------------------- 29 * Rec #0x17 slt: 0x26 objn: 52737(0x0000ce01) objd: 52737 tblspc: 0(0x00000000) 30 * Layer: 11 (Row) opc: 1 rci 0x00 31 Undo type: Regular undo Begin trans Last buffer split: No 32 Temp Object: No 33 Tablespace Undo: No 34 rdba: 0x00000000 35 *----------------------------- 36 uba: 0x008003c0.0113.16 ctl max scn: 0x0000.000d12f4 prv tx scn: 0x0000.000d133f 37 txn start scn: scn: 0x0000.000d189d logon user: 0 38 prev brb: 8389563 prev bcl: 0 39 KDO undo record: 40 KTB Redo 41 op: 0x04 ver: 0x01 42 op: L itl: xid: 0x000a.021.0000013e uba: 0x00800011.00f1.2a 43 flg: C--- lkc: 0 scn: 0x0000.000d1240 44 KDO Op code: URP row dependencies Disabled 45 xtype: XA flags: 0x00000000 bdba: 0x0040ef02 hdba: 0x0040ef01 46 itli: 1 ispac: 0 maxfr: 4863 47 tabn: 0 slot: 2(0x2) flag: 0x2c lock: 0 ckix: 12 48 ncol: 2 nnew: 1 size: -1 49 col 1: [ 5] 6e 6f 73 6c 71 50 51 End dump data blocks tsn: 1 file#: 2 minblk 960 maxblk 960 52 53 54 SQL> set serveroutput on 55 SQL> declare n varchar2(20); 56 2 begin 57 3 dbms_stats.convert_raw_value('6e6f736c71',n); 58 4 dbms_output.put_line(n); 59 5 end; 60 6 / 61 noslq 62 63 PL/SQL procedure successfully completed. 64 65 SQL> 66 --通過這個(gè)測(cè)試,清楚了Oracle 通過ITL 找到數(shù)據(jù)的前鏡像了。
?
轉(zhuǎn)載于:https://www.cnblogs.com/polestar/archive/2013/03/11/2953716.html
總結(jié)
以上是生活随笔為你收集整理的Oracle Block浅析2:ITL(Interested Transaction List)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 忘不了的昨天是什么歌?
- 下一篇: 求这张古风图片的高清以上,左边是男的递手