Oracle redo與undo


Undo and redo

Oracle最重要的兩部分數據,undo 與redo,redo(重做信息)是oracle在線(或歸檔)重做日志文件中記錄的信息,可以利用redo重放事務信息,undo(撤銷信息)是oracle在undo段中記錄的信息,用於撤銷或回滾事務。

1 redo

   重做日志文件redo log,是數據庫的事務日志,oracle維護着2類重做日志,在線重做日志文件和歸檔重做日志文件,歸檔日志文件就是重做日志的副本,系統將日志文件填滿時arch進程會在另一個位置建立一個在線重做日志的副本

   每個oracle數據庫至少有2個重做日志組,以便切換日志,每個日志組至少有1個日志組成員,這些在線重做日志文件是以循環寫的方式使用,

2 undo

 你對數據庫執行修改時,數據庫會生成undo信息,以便回滾到更改前的狀態,undo用於取消一條語句或一組語句的作用,undo在數據庫內部存放在一組特殊的段中,

為undo段(回滾段 rollback segment),利用undo,數據庫只是邏輯的恢復到原來的樣子,所有修改都邏輯的取消,但是數據結構以及數據塊本身在回滾后可能不大相同,

 對於undo生成對於直接路徑操作不適用,直接路徑操作能夠繞過表上的undo生成。

SQL> set autotrace traceonly statistics
SQL> select * from t;--not first execute
no rows selected
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        995  bytes sent via SQL*Net to client
        374  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

SQL> insert into t select * from all_objects;
49789 rows created.
SQL> rollback;
Rollback complete.
SQL> select * from t;
no rows selected
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        689  consistent gets -----I/O
          0  physical reads
          0  redo size
        995  bytes sent via SQL*Net to client
        374  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

Insert導致一些塊增加到表的高水位線(HWM),這些塊沒有因為回滾而消失,

select extent_id, bytes, blocks from user_extents

    where segment_name = 'X' order by extent_id; 分配給表的存儲空間—這個表沒有使用任何區段

3 undo 跟redo如何協作

盡管undo信息存儲在undo表空間或undo段中,但也會受到redo保護,會把undo信息當成表數據或索引數據一樣,對undo的修改會生成一些redo,將記入重做日志,

將undo數據增加到undo段中,並像其他部分的數據一樣,在緩沖區緩存中得到緩存

 Insert-update-delete場景

  3.1 insert

   Insert語句,都會生成redo跟undo信息,插入發生后,如下圖

緩存了一下已修改的undo塊,索引塊和表數據塊,這些塊得到重做日志緩沖區相應條目的保護

   1假象現在系統崩潰,sga全部被清空,但是我們不需要sga的中的任何內容,重啟動時就好像這個事務就沒發生過,沒有將任何修改的塊刷新輸出到磁盤,

也沒有任何redo信息刷新輸出到磁盤,我們不需要這些undo或redo信息來實現實例失敗恢復

   2假象:緩沖區緩存已滿

     Dbwr進程要把已修改的塊從緩存輸出到磁盤,首先要求lgwr進程將保護這些數據庫的redo條目輸出到磁盤,dbwr在將任何修改的塊輸出到磁盤之前,都必須要求lgwr進程先刷新輸出到redo日志,

 

3.2 update

  Update所帶來的工作與insert大體一樣,不過undo信息量更大,update,要保存系統的前映像,

 

緩沖區中會有更多的undo塊,為了撤銷update,如果必要,已修改的數據庫表和索引都會存在緩存中,其中重做日志有的已經輸出到磁盤,有的還在redo buffer 中

   1 系統崩潰:啟動時,oracle會讀取重做日志,給定系統的當前狀態,利用重做日志文件中對應的插入的redo條目,並利用仍在緩沖區中對應的redo條目,oracle會前滾插入,連接斷開,oracle發現事務從未提交,因此將其回滾,利用undo,

   2 應用回滾事務

   Oracle發現這個事務的undo信息可能緩存在undo段中,也肯能已經刷新輸出到磁盤,會把und信息應用到緩存中的數據和索引上,不在緩存中,則先要讀入到緩存,恢復其原來的行,並刷新輸出數據文件,

    回滾過程不涉及重組日志,只有恢復和歸檔才會讀取重做日志,重做日志是用來寫的,不用於讀,

  3 delete

   Delete 會生成undo日志,塊將被修改,並把redo日志發送到重做日志緩沖區,與update類似

 4 commit

   已經修改的塊放在緩沖區緩存中,可能已經輸出到磁盤,重做這個事務所需的全部redo都安全的存放在磁盤上,undo信息會一直存在,除非undo段回繞並重用了這些undo塊,

4 提交和回滾處理

   Commit:commit並沒有做太多的工作,

Commit開銷,頻繁提交,會增加與數據庫的往返同學,如果每個記錄都提交,生成的往返通信量會大得多,每次提交時,必須等待redo寫到磁盤,這會導致等待

 commit之前可能:

 已經在sga中生成了undo 塊,已經在sga中生成了已修改的數據塊,已經在sga中生成了對應的2想的redo信息,取決於前3項的大小,已經這些花費的時間,前面的數據可能已經輸出到磁盤,已經得到全部鎖需要的鎖

 在實際commit時,

  1為事務生成一個scn(系統改變號),scn用於保證事務的順序,並支持失敗恢復,scn還用於保證數據庫中的讀一致性和檢查點,每次有人commit,scn都會增加1。

  2 Lgwr進程會將重做日志緩沖區中的redo信息全部輸出到磁盤,並把scn記錄到redolog中,這一步已經真正提交,回車v$transaction中刪除。

  3 V$lock記錄中我們會話持有的鎖全部釋放。4 如果事務修改的某些塊還在緩沖區存在,則已一種快速的模式訪問並清理,塊清除。

   Rollback 。撤銷所有的修改,從undo中讀取數據,逆向執行前面所做的事情,釋放所持有的鎖,

5 分析redo

Redo管理是數據庫的一個串行點,任何oracle實例只有一個lgwr,

  5.1 測量redo

 

SQL> set autotrace traceonly statistics;
SQL> truncate table t;
Table truncated.
SQL> insert into t select * from all_objects;
49788 rows created.
Statistics
----------------------------------------------------------
       6702  recursive calls
       6822  db block gets
      83402  consistent gets
          2  physical reads
    5625720  redo size
        672  bytes sent via SQL*Net to client
        575  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
         14  sorts (memory)
          0  sorts (disk)
      49788  rows processed
SQL> truncate table t;
Table truncated.

 對於noarchivelog模式的數據庫進行直接路徑加載,如果是archivelog模式,必須把表設置為nologging模式

SQL> insert /*+ APPEND */ into t select * from all_objects;
49788 rows created.
Statistics
----------------------------------------------------------
       6244  recursive calls
       1254  db block gets
      82000  consistent gets
          2  physical reads
      57016  redo size
        659  bytes sent via SQL*Net to client
        589  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
      49788  rows processed

5.2 能關掉重做日志程序嗎

     答案是不能的,重做日志是必不可少的,dba如果把db設置為force logging模式,在這種情況下,任何操作都會記錄日志,

     select force_logging from v$database

      5.2.1 在sql中設置nologging

         有些sql語句和操作支持使用nologging,有些特定的操作會比不使用nologging生成的redo要少的多,

          在歸檔模式下,創建表使用nologging,看與不適用nologging的redo的比較

         查看歸檔模式: cmd》archive log list

         select log_mode from v$database

         修改到歸檔模式:1 alter system set log_archive_dest_1=’location=f:\

         Mydb\acrhive’;將歸檔日志放到指定的目錄,默認在安裝rdbms目錄下

        關閉 shutdown immediate

        startup mount 模式

        alter database archivelog

        alter database open

       歸檔未歸檔的文件 alter system archive log all

       SQL> alter system set log_archive_dest_1='location=f:\mydb\archivelog';

      System altered.

    創建一個函數,返回redo的大小

create or replace function get_stat_val( p_name in varchar2 ) return 
number 
    as 
         l_val number; 
    begin 
       select b.value 
         into l_val 
        from v$statname a, v$mystat b 
         where a.statistic# = b.statistic# 
           and a.name = p_name; 
  
       return l_val; 
   end;

 

 

create table t

   NOLOGGING as select * from all_objects

  Nologging注意:

  1 還是會生成一定的redo,該redo主要是保護數據字典

       2 此時nologging在建表時避免生成redo,但是在后續操作中insert update,delete都會生成redo

       3 在archivelog模式的數據庫中,使用了nologging之后,要趕快備份操作所創建的數據

    5.2.2 在索引上使用nologging

        noarchivelog模式下,

            create index test_y on test2(y) select get_stat_val('redo size') from dual

            alter index test_y rebuild

            select get_stat_val('redo size') from dual    alter index test_y nologging 之后,redo相差不多

           noarchivelog模式下,索引createrebuild不會記錄到redo

           archivelog下才有區別

      Nologging小結:采用nologging模式執行以下操作

           1 索引的創建和alter(重建)

           2 表的批量insert(用過append直接路徑加載或sqlldr直接路徑加載),表數據不生成redo,但是索引的所有修改會生成redo

           3 lob操作(對大對象的操作不需要生成redo)

           4 用過create as select 創建table

           5 各種alter table 操作

 6 臨時表和redo/undo

      臨時表不會為他們的塊生成redo信息,對臨時表的操作是不可恢復的,修改臨時表的一個塊時不會將修改記錄到重做日志中,不過臨時表會生成undo,

      臨時表可以有約束,正常表有的臨時表都可以有,

      關於臨時表的dml操作

      Insert 不會生成undo

      Update生成的undo比正常表少一半

      Delete會生成一樣的undo

     另外考慮臨時表上的索引,索引的修改也會生成undo

  7 分析undo

    7.1 什么操作會生成最多最少的undo

          存在索引,對表的操作會生成更多的undo,insert最少,delete最多的undo,

         大量更新前,索引刪除后在重建

 

    7.2 ora-1555 snapshot too old 快照太舊

         1555錯誤與數據破壞跟數據丟失沒有關系,唯一的影響是不能進行查詢處理

        導致1555的3個原因

         1 undo段太小,不足以在系統下執行工作

         2程序跨commit獲取

         3 塊清除

         由於數據庫的讀一致性,導致會從undo中讀取信息,undo太小,被回繞利用,查詢就不能繼續,

          解決辦法:1 適當的設置undo_retention(要大於運行最長事務的所需的時間),可以用v$undostat undostat來確定長時間運行的查詢的持續時間,另外保證磁盤上預留了足夠的空間,使undo段能根據所需要的undo_retention字段增加

          2使用手動管理undo段增加其大小,建議自動管理undo段

          3減少查詢的時間(調優),最好的辦法

          4 收集相關的統計信息,大批量的update跟insert會導致塊清除,在大量更新后,收集表的統計信息

      select * from v$undostat

     1 undo段確實太小

        create undo tablespace undo_small

              datafile '/tmp/undo.dbf' size 2m  autoextend off 創建一個小的undo空間

       alter system set undo_tablespace = undo_small;

      create table t  as  select *  from all_objects   order by dbms_random.random;

      exec dbms_stats.gather_table_stats( user, 'T', cascade=> true );收集統計信息

   進行一個大量的更新,同時在另一個會話查詢,

     回滾表空間設置為自動增長(相應的數據文件)

       alter database datafile '/tmp/undo.dbf' autoextend on next 1m maxsize 2048m;

    查看大小 select bytes/1024/1024 from dba_data_files where tablespace_name = 'UNDO_SMALL'

  解決辦法1 保證事務大小適當,不要過於頻繁的提交

          2 使用dbms_stats掃描相關的對象

          3 允許undo表空間自動擴大,

          4 減少查詢的時間(先嘗試做)

 Undo信息有專門的undo表空間(對於的數據文件),使用undo信息前必須在緩沖區中sga中,可能在磁盤的undo信息要讀到緩沖區中使用,undo是可繞回使用,可自動擴展


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM