Oracle基本資料改變原理淺析(redo與undo)--oracle核心技術讀書筆記一,redo--oracle

來源:互聯網
上載者:User

Oracle基本資料改變原理淺析(redo與undo)--oracle核心技術讀書筆記一,redo--oracle

        在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的兩點疑問,

1、停電的情況,事務不會被提交。實際上,如果細說redo apply和undo apply過程的話,是這樣的:資料庫先用redo恢複資料檔案(包括普通permanent資料表空間的資料檔案和undo資料表空間的資料檔案),這就是你說的“恢複系統到失敗點”,這之後開資料庫執行個體會被開啟,執行個體開啟後,執行個體會根據undo中記錄的資訊復原未提交的事務。
以下是原廠手冊中的說明:
In the context of recovery, the undo information is used to undo the effects of uncommitted transactions, once all the datafile changes from the redo logs have been applied to the datafiles. The database is actually opened before the undo is applied.

You should not have to concern yourself with undo segments or manage them directly as part of your backup and recovery process.

2、磁碟損壞的情況,這種恢複也叫介質恢複,在恢複(recover)之前,需要使用備份先還原(restore)損壞的檔案。
 
oracle redo 與undo

1、記錄資料庫的變化,比如update、insert、delete等動作。
2、並非直接寫入undo資料表空間,只有當髒資料區塊達到一定程度才寫入。
 

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.