一. 說明
Oracle的一個資料區塊裡的SCN有三種,分別是塊頭的SCN, CSC (cleanout SCN)和ITL中的commit SCN。 關於block 裡的具體資訊,可以把block dump 出來,進行查看。 這個在我之前的blog裡有整理:
Oracle datafile block 格式 說明
http://blog.csdn.net/tianlesoftware/article/details/6654786
OraceITL(InterestedTransaction List) 說明
http://blog.csdn.net/tianlesoftware/article/details/6573988
Block的cache header部分,記錄著一個block scn,它是當前塊最後一次變更的時間戳記,確切說,這個更新並不是指itl上的scn的最新更新,在接下來delayed block cleanout下的slot重用情況下,可以看到blockscn並不等於itl上的最後一次更新的scn。可以通過dump獲得block scn/last itl scn 和發布ora_rowscn語句獲得last itl scn。
Oracle ORA_ROWSCN 偽列 說明
http://blog.csdn.net/tianlesoftware/article/details/6658529
Eachdata block in a datafile contains an SCN, which is the SCN at which the lastchange was made to the block. During an incremental backup, RMAN reads the SCNof each data block in the input file and compares it to the checkpoint SCN ofthe parent incremental
backup. RMAN reads the entire file every time whether ornot the blocks have been used.
發布transaction後,未提交之前,block scn是不會改變的,對應的itl中也並不做scn記錄。Block scn的改變,確切的說不是在發布commit之時(因為有delayed block cleanout的情況存在),而是在transaction對應的itl獲得commit scn之時。
cleanout分為2鐘,一種是fast commit cleanout,另一種是delayed block cleanout.
oracle有一個modified block list結構,用來記錄每個transaction更改過的block,每個transaction大約可以記錄10% buffer cache這多的modified block。這部分block就是當發生commit的時候,oracle可以根據modified block list定位到那些塊並做fast commit cleanout。如果一個transaction修改的塊超過10% buffer cache,那麼超過的塊就執行delayed
block cleanout。
當做fast commit cleanout時,oracle不會清理 Row locks lb標誌位,ITL lck標誌位。
另一種情況是delayed block cleanout,當transaction還未commit或rollback時modified block已經被寫回磁碟,當發生commit時oracle並不會把block重新讀入做cleanout,這樣成本太高,而是把cleanout留到下一次對此塊的dml時來完成。當delayed cleanout時候如果undo segment header的transaction table slot還沒有被覆蓋,那麼可以找回該事務遞交的exact scn,如果slot已經被覆蓋,那麼將會使用undo
segment header中的control scn來做為upper bound scn。
當發生fast commit cleanout,系統將transaction提交時刻的scn作為commit scn,更新block上 itl和undo segment header的Transaction table的slot上的 scn,並修改block scn,三者是一致的。
發生delayed block cleanout的時候,之前的transaction commit更新的只是Transaction table,而並未做block上的處理,等待下次使用此block的時候,更新block scn和itl狀態。block scn和itl的更新又分2種情況:
(1)當不產生slot重用的時候(ITL不重用), delayed block cleanout時,根據Transaction table裡面的資訊,更新block scn和itl上的Scn/Fsc為transaction曾經提交時候的scn。
(2)當產生slot重用的時候(重用ITL),更新對應itl上scn為control scn,而block scn 為delayed block cleanout發生時刻的scn。
說明:ITL 中SCN 和 FSC 的區別
dump block的ITL 的資訊如下:
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000e.007.00000236 0x00000000.0000.00C-U- 0 scn 0x0000.005b1f7f
0x02 0x000c.005.000003b4 0x01401727.0144.13C--- 0 scn 0x0000.005bbf0b
0x03 0x0011.007.00000406 0x0140015b.00c7.57--U- 483 fsc 0x0000.005bdee1
這裡的SCN和FSC其實就是這個ITL對應的事務提交時候的SCN,那麼這裡所有槽位上的最大的一個SCN號就表示這個BLOCK最後被更新的時候的SCN。每一個事務對應一個itl 記錄。如果該事務沒有涉及延時塊清除,那麼顯示的FSC。 如果是延時塊清除(delayed block cleanout),那麼顯示的就是SCN。
在ITL資訊中有一個顯示的Flag的狀態,FLAG在block中佔用1個位元組大小。 不同flag 標記的意義如下:
---- = transaction is active, or committedpending cleanout
C--- = transaction has been committed andlocks cleaned out
-B-- = this undo record contains the undofor this ITL entry
--U- = transaction committed (maybe longago); SCN is an upper bound
---T = transaction was still active atblock cleanout SCN
二. 測試2.1 fast commit cleanout
SYS@anqing2(rac2)> create table fcc(idnumber);
Table created.
SYS@anqing2(rac2)> insert into fccvalues(1);
1 row created.
SYS@anqing2(rac2)> insert into fccvalues(2);
1 row created.
SYS@anqing2(rac2)> commit;
Commit complete.
SYS@anqing2(rac2)> selectdbms_rowid.rowid_block_number(rowid),ora_rowscn from fcc;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)ORA_ROWSCN
----------------------------------------------
305906 7262675
305906 7262675
--剛才插入的2條記錄都存放在block305906裡,並且ora_rowscn也一樣。
對fcc 表進行update:
SYS@anqing2(rac2)> update fcc set id=3where id=1;
1 row updated.
SYS@anqing2(rac2)> update fcc set id=4where id=2;
1 row updated.
SYS@anqing2(rac2)> selectdbms_rowid.rowid_block_number(rowid),ora_rowscn from fcc;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)ORA_ROWSCN
----------------------------------------------
305906 7262675
305906 7262675
--ora_rowscn 沒有變化
SYS@anqing2(rac2)> commit;
Commit complete.
SYS@anqing2(rac2)> selectdbms_rowid.rowid_block_number(rowid),ora_rowscn from fcc;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)ORA_ROWSCN
----------------------------------------------
305906 7262794
305906 7262794
--ora_rowscn 已經改變,這個在ora_rowscn 那篇blog裡有說明,這個ora_rowscn是從block header SCN 裡讀取的。
2.2 delayed block cleanout
--.建立一個小undo資料表空間.
SYS@dave2(db2)> create undo tablespaceundotbs2 datafile '/u01/app/oracle/oradata/dave2/undotbs02.dbf' size 1M;
Tablespace created.
SYS@dave2(db2)> alter system setundo_tablespace='undotbs2';
System altered.
--建立測試表並insertdata
SYS@dave2(db2)> create table dbc(idnumber);
Table created.
SYS@dave2(db2)> insert into dbcvalues(1);
1 row created.
SYS@dave2(db2)> insert into dbc values(2);
1 row created.
SYS@dave2(db2)> commit;
Commit complete.
SYS@dave2(db2)> selectdbms_rowid.rowid_block_number(rowid) block,dbms_rowid.rowid_relative_fno(rowid) fileno, ora_rowscn from dbc;
BLOCK FILENO ORA_ROWSCN
---------- ---------- ----------
115346 1 2147768913
115346 1 2147768913
--update table
SYS@dave2(db2)> update dbc set id=8where id=1;
1 row updated.
SYS@dave2(db2)> update dbc set id=9where id=2;
1 row updated.
--得到XIDUSN,XIDSLOT的使用方式,後續發布重用指令碼
SYS@dave2(db2)> selectxidusn,xidslot,xidsqn from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
16 18 5
--重新整理buffer cache,如果出現事務遞交前modified block就被flush回硬碟,那麼將發生delayed block cleanout。
SYS@dave2(db2)> alter system flush buffer_cache;
System altered.
SQL> commit;
Commit complete
--大概的commit scn
SYS@dave2(db2)> selecttimestamp_to_scn(systimestamp) from dual;
TIMESTAMP_TO_SCN(SYSTIMESTAMP)
------------------------------
2147770572
--使用如下指令碼,重用XIDUSN 16 XIDLOT 18
/* Formatted on 2011/8/4 15:47:15(QP5 v5.163.1008.3004) */
CREATE TABLE goon
AS
SELECT *
FROMdba_objects
WHERE 1 = 2;
/* Formatted on 2011/8/4 15:45:12(QP5 v5.163.1008.3004) */
CREATE OR REPLACE PROCEDUREproc_go_break_reuse (v_XIDUSN NUMBER,
v_XIDSLOT NUMBER,
v_XIDSQN NUMBER)
/* ————————————————–
Description:It’s used to maketransaction slot reused
—————————————————*/
AS
nsid NUMBER;
TYPEtransaction_record_type IS RECORD
(
XIDUSN NUMBER,
XIDSLOT NUMBER,
XIDSQN NUMBER
);
transaction_record transaction_record_type;
BEGIN
SELECT SYS_CONTEXT ('userenv', 'sid') INTO nsid FROM DUAL;
LOOP
INSERT INTO goon
SELECT *
FROMdba_objects
WHERE ROWNUM < 100;
SELECTXIDUSN,XIDSLOT,XIDSQN
INTOtransaction_record
FROMv$transaction a,v$session b
WHERE a.ADDR = b.TADDR AND b.SID = nsid;
IF ( transaction_record.XIDUSN=v_XIDUSN
ANDtransaction_record.XIDSLOT =v_XIDSLOT
ANDtransaction_record.XIDSQN >v_XIDSQN)
THEN
GOTOresue_end;
END IF;
COMMIT;
DELETE FROM goon;
SELECTXIDUSN,XIDSLOT,XIDSQN
INTOtransaction_record
FROMv$transaction a,v$session b
WHERE a.ADDR = b.TADDR AND b.SID = nsid;
IF ( transaction_record.XIDUSN=v_XIDUSN
AND transaction_record.XIDSLOT=v_XIDSLOT
ANDtransaction_record.XIDSQN >v_XIDSQN)
THEN
GOTOresue_end;
END IF;
COMMIT;
END LOOP;
<<resue_end>>
COMMIT;
END;
--呼叫指令碼
SYS@dave2(db2)> execproc_go_break_reuse(16,18,5);
PL/SQL procedure successfully completed.
--產生延時塊清除,記錄相應scn號
SYS@dave2(db2)> select * from dbc;
ID
----------
8
9
--發生延時塊清除時候的大概scn
SYS@dave2(db2)> selecttimestamp_to_scn(systimestamp) from dual;
TIMESTAMP_TO_SCN(SYSTIMESTAMP)
------------------------------
2147771961
--最後一次itl 上的 commit scn
SYS@dave2(db2)> selectdbms_rowid.rowid_block_number(rowid) block,dbms_rowid.rowid_relative_fno(rowid) fileno, ora_rowscn from dbc;
BLOCK FILENO ORA_ROWSCN
---------- ---------- ----------
115346 1 2147771334
115346 1 2147771334
--dump undo header
--查看正在使用的復原段
SYS@dave2(db2)> selectxidusn,xidslot,xidsqn,ubablk,ubafil,ubarec from v$transaction;
XIDUSN XIDSLOT XIDSQN UBABLK UBAFIL UBAREC
---------- ---------- ---------- -------------------- ----------
13 41 7 42 7 6
XIDUSN: rollback ID
UBABLK: datafile ID
但是這裡我們要使用我們當時的undo塊,即我們之前查詢的XIDUSN=16
SYS@dave2(db2)> select usn,name fromv$rollname where usn=16;
USN NAME
---------- ------------------------------
16 _SYSSMU16$
alter system dump undo header '_SYSSMU13$';
SYS@dave2(db2)> alter system dump undoheader '_SYSSMU16$';
System altered.
SYS@dave2(db2)> oradebug setmypid
Statement processed.
SYS@dave2(db2)> oradebug tracefile_name
/u01/app/oracle/admin/dave2/udump/dave2_ora_11079.trc
TRNCTL:: seq: 0x0003 chd: 0x002a ctl: 0x0029 inc: 0x00000000 nfb: 0x0001
mgc: 0x8201 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe)
uba: 0x01c0007a.0003.30 scn: 0x0000.800464f4 --control SCN
SYS@dave2(db2)> select to_number('800464f4','xxxxxxxxxxx')from dual;
TO_NUMBER('800464F4','XXXXXXXXXXX')
-----------------------------------
2147771636
Version: 0x01
FREE BLOCK POOL::
uba: 0x01c0007a.0003.30 ext: 0x2 spc: 0x572
uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0
uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0
uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0
uba: 0x00000000.0000.00 ext: 0x0 spc: 0x0
TRNTBL::
index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt
------------------------------------------------------------------------------------------------
0x00 9 0x00 0x0007 0x0001 0x0000.80046548 0x01c00068 0x0000.000.00000000 0x00000001 0x00000000 1312472853
0x01 9 0x00 0x0007 0x0002 0x0000.80046554 0x01c00068 0x0000.000.00000000 0x00000001 0x00000000 1312472853
0x02 9 0x00 0x0007 0x0003 0x0000.80046560 0x01c00079 0x0000.000.00000000 0x00000001 0x00000000 1312472853
0x03 9 0x00 0x0007 0x0004 0x0000.8004656c 0x01c00079 0x0000.000.00000000 0x00000001
--dump block 115346
SYS@dave2(db2)> alter system dumpdatafile 1 block 115346;
System altered.
SYS@dave2(db2)> oradebug tracefile_name
/u01/app/oracle/admin/dave2/udump/dave2_ora_11079.trc
Start dump data blocks tsn: 0 file#: 1minblk 115346 maxblk 115346
buffer tsn: 0 rdba: 0x0041c292 (1/115346)
scn: 0x0000.80046634 seq:0x01 flg: 0x04 tail: 0x66340601
--這個scn 就是blockscn,將 0x0000.80046634轉成數字:
SYS@dave2(db2)> select to_number('80046634','xxxxxxxxx')from dual;
TO_NUMBER('80046634','XXXXXXXXX')
---------------------------------
2147771956
該值與前面延時塊清除時的SCN:2147771961差不多,所以這裡應該是延時塊清除的時候的scn。
frmt: 0x02 chkval: 0x2974 type: 0x06=transdata
.....
Block header dump: 0x0041c292
Object id on Block? Y
seg/obj: 0xdf46 csc: 0x00.80046634 itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0010.012.00000005 0x01c0005e.0001.25 C-U- 0 scn 0x0000.800463c6
0x02 0x000f.008.00000005 0x01c00051.0002.17 C--- 0 scn 0x0000.80045e0b
其中ITL 中的XID 格式為:usn#.slot#.wrap#
SYS@dave2(db2)> selectto_number('10','xxxxxxxxxxx') from dual;
TO_NUMBER('10','XXXXXXXXXXX')
-----------------------------
16
SYS@dave2(db2)> select to_number('12','xxxxxxxxxxx')from dual;
TO_NUMBER('12','XXXXXXXXXXX')
-----------------------------
18
SYS@dave2(db2)> selectto_number('00000005','xxxxxxxxxxx') from dual;
TO_NUMBER('00000005','XXXXXXXXXXX')
-----------------------------------
5
和之前V$TRANSACTION查詢的一致。
SYS@dave2(db2)> selectto_number('800463c6','xxxxxxxxxxx') from dual;
TO_NUMBER('800463C6','XXXXXXXXXXX')
-----------------------------------
2147771334
--等於最後一次commit的SCN
SYS@dave2(db2)> select to_number('80045e0b','xxxxxxxxxxx')from dual;
TO_NUMBER('80045E0B','XXXXXXXXXXX')
-----------------------------------
2147769867
說明:
在前面提到,當slot重用時,更新對應itl上scn為control scn。 但是我這裡的dump undo的control SCN 為2147771636。但itl 的scn為2147771334,是最後一次commit的SCN. 所以說這個測試並沒有證明這個結論。實驗步驟還有待重新完善。
題外話一句: 結果有時候並不重要,重要的是分析的過程。
參考:http://www.easyora.net/blog/scn_block_scn.html
-------------------------------------------------------------------------------------------------------
Blog: http://blog.csdn.net/tianlesoftware
Weibo: http://weibo.com/tianlesoftware
Email: dvd.dba@gmail.com
DBA1 群:62697716(滿); DBA2 群:62697977(滿) DBA3 群:62697850(滿)
DBA 超級群:63306533(滿); DBA4 群: 83829929(滿) DBA5群: 142216823(滿)
DBA6 群:158654907(滿) 聊天 群:40132017(滿) 聊天2群:69087192(滿)
--加群需要在備忘說明Oracle資料表空間和資料檔案的關係,否則拒絕申請