標籤:oracle redo undo 資料改變
在oracle中我們做一些更新操作,oracle底層是怎麼流轉的呢,就是這篇文章要講解的。
一. 原理
假設我們在一個已經更新了很多條分散記錄的OLTP系統中,更新了一行資料。那麼這個更新的真實步驟如下:
1. 建立一個重做改變向量,描述如何往undo塊插入一條undo記錄(也就是描述undo塊的改變)
2. 建立一個重做改變向量,描述資料區塊的改變(也就是資料的改變)
3. 合并這兩個重做改變向量為一條日誌記錄,並寫到重做日誌緩衝區(便於今後重做)
4. 向undo塊插入undo記錄(便於今後回退)
5. 改變資料區塊中的資料(這裡才真正改變資料)
下面我們通過一個例子來展示這個過程。
二. 實踐
我們先建立一個表,然後更新表中資料第一個塊的第3,4,5,條記錄,並且在每更新一條後會穿插更新第二個塊的一條記錄。也就是這個更新操作會更新6條記錄,他會改變每一個記錄的第三列------ 一個varchar2類型的欄位,將其由xxxxxx(小寫6個字元)改變為YYYYYYYYYY(大寫10個字元)。
1. cmd命令列 以sys 使用者登入
2. 準備工作(建立幾個預存程序,用來轉儲塊,轉儲重做日誌等)
這些指令碼見:http://download.csdn.net/detail/liwenshui322/7912909
3. 準備工作(主要清除資源回收筒刪除資訊,設定塊讀取代價,估值計算依據等)
start setenvset timing offexecute dbms_random.seed(0)drop table t1;beginbeginexecute immediate 'purge recyclebin'; --清空資源回收筒exceptionwhen others then null;end;begindbms_stats.set_system_stats('MBRC',8); --多塊讀取為8塊dbms_stats.set_system_stats('MREADTIM',26); --對塊讀取平均時間為26毫秒dbms_stats.set_system_stats('SREADTIM',12); --單塊讀取平均時間為30毫秒dbms_stats.set_system_stats('CPUSPEED',800); --cpu每秒可執行800,000,000個操作exceptionwhen others then null;end;beginexecute immediate 'begin dbms_stats.delete_system_stats; end;'; --刪除系統統計資訊exceptionwhen others then null;end;beginexecute immediate 'alter session set "_optimizer_cost_model"=io'; --基於io來計算估值exceptionwhen others then null;end;end;/
4. 建立表與索引
create table t1asselect2 * rownum - 1id,rownumn1,cast('xxxxxx' as varchar2(10))v1,rpad('0',100,'0')paddingfromall_objectswhererownum <= 60union allselect2 * rownumid,rownumn1,cast('xxxxxx' as varchar2(10))v1,rpad('0',100,'0')paddingfromall_objectswhererownum <= 60;create index t1_i1 on t1(id);
5. 統計表資訊
begindbms_stats.gather_table_stats(ownname => user,tabname =>'T1',method_opt => 'for all columns size 1');end;/
6.查看錶佔用的塊情況,和每一個塊有多少條資料
select dbms_rowid.rowid_block_number(rowid)block_number, count(*)rows_per_blockfrom t1 group by dbms_rowid.rowid_block_number(rowid)order byblock_number;
我們會看到,總共佔用兩個塊,每一個塊都有60條記錄
7. 轉儲資料區塊
alter system switch logfile;execute dump_seg('t1')
8. 做更新
update/*+ index(t1 t1_i1) */t1setv1 = 'YYYYYYYYYY'whereid between 5 and 9;
9. 轉儲更新塊之後的資料區塊和undo塊(發生檢查點語句執行後,下一個語句等5,6s再執行,發生檢查點只是告訴oracle將髒資料寫入磁碟,需要一點時間)
pause Query the IMU structures now (@core_imu_01.sql)
alter system checkpoint;--發生檢查點,讓資料寫到磁碟
execute dump_seg('t1')execute dump_undo_block 10. 轉儲redo塊
rollback;commit;execute dump_log
11. 定位轉儲資訊檔位置
select sid from v$mystat where rownum=1;--查詢結果傳入下一個sqlSELECT d.value||'/'||lower(rtrim(i.instance, chr(0)))||'_ora_'||p.spid||'.trc' trace_file_name from ( select p.spid from v$session s, v$process p where s.sid='133' and p.addr = s.paddr) p, ( select t.instance from v$thread t,v$parameter v where v.name = 'thread' and (v.value = 0 or t.thread# = to_number(v.value))) i, ( select value from v$parameter where name = 'user_dump_dest') d;
12. 開啟檔案
下面看幾個關鍵區段,我們看第一個塊的第5條資料,我們將這一行資料的第三列由xxxxxx改成了YYYYYYYYYY。
update之前:
tab 0, row 4, @0x1d3ftl: 117 fb: --H-FL-- lb: 0x0 cc: 4col 0: [ 2] c1 0acol 1: [ 2] c1 06col 2: [ 6] 78 78 78 78 78 78col 3: [100] 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
我們看到col2長度是6,然後是6個78(x的十六進位ASCII碼是78)。
update之後:
tab 0, row 4, @0x2a7tl: 121 fb: --H-FL-- lb: 0x2 cc: 4col 0: [ 2] c1 0acol 1: [ 2] c1 06col 2: [10] 59 59 59 59 59 59 59 59 59 59col 3: [100] 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
我們可以看到col2長度變成了10,是10個59(Y的十六進位ASCII碼是59),同時我們看到行地址由@0x1d3f變成了@0x2a7,說明這一行的空間容不下新增的資料,換了一個地方。(檢查行目錄也能發現這一點)同時,我們能看到lb(lock byte)由0x0變成了0x2,表明這條記錄被該塊事務槽列表中的第二個事務槽所標識的事務鎖定。事務槽可以在塊首部看到。
下面,看第5條資料在redo裡面儲存的是什麼(怎麼保證資料的重做),在檔案裡面搜尋 tabn: 0 slot: 4(0x4) flag: 0x2c lock: 2, 我們會找到這麼一段描述
CHANGE #6 TYP:0 CLS:1 AFN:1 DBA:0x004161c9 OBJ:77125 SCN:0x0000.002796b6 SEQ:2 OP:11.5 ENC:0 RBL:0KTB Redo op: 0x02 ver: 0x01 compat bit: 4 (post-11) padding: 0op: C uba: 0x00c0055a.0123.27KDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000 bdba: 0x004161c9 hdba: 0x004161c8itli: 2 ispac: 0 maxfr: 4863tabn: 0 slot: 4(0x4) flag: 0x2c lock: 2 ckix: 50ncol: 4 nnew: 1 size: 4col 2: [10] 59 59 59 59 59 59 59 59 59 59
這描述的是一個改變世界,我們看第6行 op code:是URP(更新行片),第七行我們可以看到更新的塊地址bdba和所在段的地址hdba。
第八行itli: 2 表明執行更新操作的事務正在使用第二個事務槽,跟資料區塊裡面看到的一致。
第九行tabn: 0 slot: 4 表明我們在更新第一張表(一個塊可能儲存多個表的資料)的第5條記錄。
最後兩行,我們可以看出這條記錄有4列(nclo:4),修改了一列(nnew:1),長度增加了4(size:4).並將第3列的值改成了YYYYYYYYYY。(儲存了修改後的資料,方便重做)
接下來,看第5條資料在undo裡面怎麼儲存的(怎麼保證資料的回退),在檔案裡面搜尋tabn: 0 slot: 4(0x4) flag: 0x2c,我們會找到如下一段描述:
*-----------------------------* Rec #0x27 slt: 0x04 objn: 77125(0x00012d45) objd: 77125 tblspc: 0(0x00000000)* Layer: 11 (Row) opc: 1 rci 0x26 Undo type: Regular undo Last buffer split: No Temp Object: No Tablespace Undo: No rdba: 0x00000000*-----------------------------KDO undo record:KTB Redo op: 0x02 ver: 0x01 compat bit: 4 (post-11) padding: 0op: C uba: 0x00c0055a.0123.25KDO Op code: URP Disabled row dependencies xtype: XA flags: 0x00000000 bdba: 0x004161c9 hdba: 0x004161c8itli: 2 ispac: 0 maxfr: 4863tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 50ncol: 4 nnew: 1 size: -4col 2: [ 6] 78 78 78 78 78 78
主要關注下面的六行資料,其實跟前面redo裡面的資料差不多,就是size=-4,col2變成了6個78(x的十六進位ASCII碼是78)。(保證資料能夠回去以前的版本)
最後,我們可以在轉儲的redo裡面尋找undo塊改變的描述,檔案裡面搜尋tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0,我們會找到如下一段描述:
CHANGE #11 TYP:0 CLS:36 AFN:3 DBA:0x00c0055a OBJ:4294967295 SCN:0x0000.002796b6 SEQ:4 OP:5.1 ENC:0 RBL:0ktudb redo: siz: 92 spc: 4078 flg: 0x0022 seq: 0x0123 rec: 0x27 xid: 0x000a.004.00000467 ktubu redo: slt: 4 rci: 38 opc: 11.1 objn: 77125 objd: 77125 tsn: 0Undo type: Regular undo Undo type: Last buffer split: No Tablespace Undo: No 0x00000000KDO undo record:KTB Redo op: 0x02 ver: 0x01 compat bit: 4 (post-11) padding: 0op: C uba: 0x00c0055a.0123.25KDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000 bdba: 0x004161c9 hdba: 0x004161c8itli: 2 ispac: 0 maxfr: 4863tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 50ncol: 4 nnew: 1 size: -4col 2: [ 6] 78 78 78 78 78 78
第五行,代表這是一個undo塊改變的描述,我們可以看到倒數幾行跟undo裡面的資料非常相似,因為這裡記錄的就是undo塊的改變。
自此,我們基本上可以看清楚oracle是怎麼描述資料的改變,然後才去真正去改變資料的。
Oracle基本資料改變原理淺析(redo與undo)--oracle核心技術讀書筆記一