1. 程式人生 > >對Oracle資料庫壞塊的理解

對Oracle資料庫壞塊的理解

1.物理壞塊和邏輯壞塊

      在資料庫中有一個概念叫做資料塊的一致性,Oracle的資料塊的一致性包括了兩個層次:物理一致性和邏輯一致性,如果一個數據塊在這兩個層次上存在不一致性,那就對應到了我們今天要要說的物理壞塊和邏輯壞塊。

      在每一個數據塊的頭部有一個校驗和欄位,每當資料塊要被寫回磁碟前,Oracle都會重新計算 這個資料塊的校驗和,並記錄到這個欄位最終寫會磁碟。下次資料塊被讀入記憶體,Oracle會重新 計算資料塊的校驗和,並和塊頭的欄位相比較,如果有差異,Oracle就知道這個資料塊有錯誤, 會報出ORA-1578錯誤。    通過校驗和欄位進行的檢查就是物理一致性檢查,這個功能可以讓Oracle檢查到所有底層的錯誤, 包括磁碟、儲存、IO子系統,所以稱做物理一致性檢查。

     在Oracle中每當要修改一個數據塊中,會先對資料塊內容做一個一致性檢查(如檢查記錄 是否被不存在的食物鎖定、記錄和索引是否對應等)。如果這種一致性檢查失敗,就會丟擲 ORA-600的Internal錯誤。當Oracle檢查到資料塊的邏輯一致性時,會嘗試對資料塊做 Cache Recovery,如果不能把資料塊恢復到一致狀態,Oracle就會把這個資料塊標誌為 Software Corrupt,當有查詢訪問到這資料塊時,也會丟擲前面ORA-1578錯誤。

      物理一致性檢查利用校驗和欄位工作,主要側重於檢查硬體故障,並不關心內容正確與否, 而邏輯一致性檢查就是側重於內容的檢查,內容檢查要比校驗和檢查複雜的多。 邏輯一致性檢查內容要多於物理一致性檢查。

2.發生壞塊的原因

       造成資料塊損壞的原因多種多樣,可是因為物理原因導致,也可能人為原因或Oracle bug導致。比較常見的人為原因異常關機、掉電、終止服務使程序異常終止,從而破壞資料的完整性,導致壞塊的產生。發生資料塊損壞的原因時,最典型的表現是遇到ORA-01578錯誤(比如在全表掃描時),有時也可能是ORA-600內部錯誤。

3.檢查資料塊的一致性

    (1)使用初始化引數檢查資料塊的一致性

     通過設定初始化引數db_block_checksum=true/false來啟用、關閉物理一致性檢查,啟用該引數這會 增加1%~2%的負載,Oracle推薦啟用該引數。在Oracle9i、10g中,預設是啟用的。

     通過設定引數db_block_checking=true可以啟用資料塊的邏輯一致性檢查。啟用該引數這會 增加1%~10%的負載,尤其DML操作越密集效能影響越大。在Oracle10g中這個引數 預設值是false,這將意味這資料庫只對System表空間做邏輯一致性檢查。

    (2)DBV工具對資料塊物理/邏輯性檢查

   詳情:http://book.51cto.com/art/201108/287893.htm

    (3)analyze命令檢查資料塊一致性

     analyze命令有很多中用法,可以完成很多功能,具體可參考:http://blog.csdn.net/tianlesoftware/article/details/7055164

     analyze命令檢查物件一致性:   analyze table tablename validate structure cascade online(offline);

     該命令同樣會執行物理和邏輯一致性檢查。除此之外,它還會檢查表和索引條目的匹配性,檢查分割槽表的記錄是否在正確的分割槽中, 檢查出的問題會放在USER_DUMP_DEST目錄的trace檔案中。

      使用該命令注意一下幾個問題:

      *當檢查分割槽表的記錄是否在正確的分割槽時,可以把檢查出來的記錄的ROWID記錄在一個特殊表中,這個表叫做invalid_rows,該表需要   使用utlvalid.sql指令碼提前建立,檢查語法:   analyze tablename validate structure into invalid_rows;  

      *如果檢查索引,這個命令會檢查資料塊和索引的一致性,但是不會確認每條記錄都有相應的索引項或這索引有對應的記錄,  如果需要這種檢查,需要使用cascade關鍵字。  

      *如果使用online子句,可以在DML操作時線上檢查一致性,只是這時不會收集物件的統計資訊;而如果使用offline表會被鎖住。

    (4)使用rman工具檢查

     *檢查資料檔案       backup check logical validate [database];        *檢查單個數據檔案       backup check logical validate datafile 1,2;        *檢查整個庫       backup check logical validate database    檢查的結果放在v$database_block_corruption這個動態檢視中。

      *這個命令對系統性能有一定的影響。

     (5)使用dbms_repair.check_object方法執行檢查       詳細可參考:http://blog.itpub.net/8494287/viewspace-1357457/

  (6)利用exp工具匯出整個資料庫可以檢測壞塊

    匯出命令在執行中會報ORA-01578錯誤,在這錯誤提示中會提示那個檔案號的檔案以及這個檔案中的哪個塊被損壞,如:ORA—01578:ORACLE 資料塊損壞(檔案號 4,塊號 35)。利用exp工具進行檢查壞塊也侷限性,對一些型別的壞塊是檢測不出來的如:HWM以上的壞塊是不會發現的、索引中存在的壞塊是不會發現的、資料字典中的壞塊是不會發現的。

4.使用BBED模擬壞塊

5.壞塊的恢復理論

       對於發生資料塊不一致的資料塊,如果當前資料庫有備份且處於歸檔模式,那麼就可以利用rman工具資料塊恢復功能對資料塊進行恢復,這種方法最簡單有效,而且可以在資料檔案線上時進行,不會發生資料丟失。對於沒有備份的資料庫發生資料塊損壞,可能會發生資料的丟失或資料不丟失,這要根據發生壞塊的所在的物件決定的,如索引塊發生損壞,資料就不會丟失,重建索引就可以了,發生資料丟失的多發生在表或分割槽表資料塊上。

5.1.不丟資料的恢復方法

    利用rman工具:

        blockrecover datafile xx block yy;--修復單個壞塊

        blockrecover corruption list;--修復全部壞塊

如果壞塊上的表最近都沒有更新,還可以利用bbed的copy命令來從一個最近的備份中copy過來一個數據塊恢復,具體不演示。

5.2.可能會丟資料的恢復方法

    5.2.1 確認壞塊型別

        當一個壞塊發生時,我們首先要確認這個塊到底是什麼樣的塊,是普通表的資料塊(分割槽表的上資料塊)、索引塊等,針對不同的壞塊型別我們來確認不同的恢復方法。

      <1>確定檔案號

       Oracle有兩種資料檔案號來標識資料檔案。絕對檔案號(Absolute File#  AFN)和相對檔案號(Relative File# RFN)。AFN是資料檔案在整個系統範圍內的編號,而RFN是資料檔案在表空間範圍內的編號。兩個檔案可能有相同的RFN,但是不會有相同的ASN。在ORA-01578中提示的檔案號是RFN,在ORA-1110中提示的檔案號是AFN,在ORA-600中提示的檔案號為AFN,從檢視中看到的檔案號、資料塊號屬於哪個segment 使用的也是AFN 。

複製程式碼

SQL> select tablespace_name,file_id "AFN",relative_fno "RFN"
  2  from dba_data_files;

TABLESPACE_NAME                       AFN        RFN
------------------------------ ---------- ----------
USERS                                   4          4
SYSAUX                                  3          3
UNDOTBS1                                2          2
SYSTEM                                  1          1
EXAMPLE                                 5          5
LIVAN_TBS                               6          6

6 rows selected.

複製程式碼

SQL> select tablespace_name,file_id "AFN",relative_fno "RFN"
  2  from dba_temp_files;

TABLESPACE_NAME                       AFN        RFN
------------------------------ ---------- ----------
TEMP                                    1          1

        --利用AFN查詢檔案         select name from v$datafile where file#=&AFN;

    <2>確認損壞資料塊的型別

複製程式碼

set lines 120
col segment_name for a20
col partition_name for a20
col owner for a10

select segment_name,partition_name,segment_type,owner,tablespace_name
from sys.dba_extents
where file_id=&AFN
and &bad_block_id between block_id and block_id + blocks-1;

複製程式碼

   5.2.2按照不同的型別設定不同的恢復策略

     <1>使用者表

        對於損害的資料塊屬於使用者表的,資料丟失時不可避免的,這時需要做的就是把其他資料塊中的資料搶救出來,而受損資料塊的資料就永久丟失了。這時的恢復策略是儘可能的減少使用者的損失。(如果這種資料損失不能接受,就必須考慮其他特殊手段來嘗試恢復受損資料塊中的資料)這種情況我們可以採用兩種辦法:        *放棄壞塊上的資料,搶救其他資料塊上的資料,並重建物件;        *把資料快標記為skiped,然後放任不管,也就是給這個資料塊打上個標籤,這樣以後所有的操作都會跳過這個資料塊。

       在處理資料表的壞塊時,也要考慮關聯物件的後續處理:

  --索引

select owner,index_name,index_type from dba_indexes where table_owner='&owner' and table_name='&semeng_name';

如果因為資料快損壞導致記錄丟失,那麼這些索引也就失效了,應該被刪除,然後重建索引。

  --主鍵

     Oracle通過對主鍵欄位建立唯一索引來實現主鍵約束,所以主鍵的處理方式和索引的處理方式一樣,重建這個唯一索引。

select owner,constraint_name,constraint_type,table_name from dba_constraints where owner='&owner' and table_name='&segment_name'  and constraint_type='P';

--指向該主鍵的外來鍵

查詢出指向該主鍵的外來鍵,主鍵外來鍵處理方法相同,都需要重建索引。

select owner,constraint_name,constraint_type,table_name from dba_constraints where r_owner='&owner' and r_constraint_name='&constraint_name';

     <2>分割槽表

    分割槽表的處理和普通表類似,確認資料屬於哪個分割槽,然後對受損的分割槽可以通過exchange操作,和一個相同表結構的空表進行交換,不影響程式的正常執行,然後與普通表相同的方法處理。

           <3>索引

      如果受損物件為索引,直接刪除索引重建就可以了。

     對於普通表索引重建需要使用 alter index ... rebuild online語法,如果不帶online關鍵字, 會依據舊的索引(包含壞塊的)重建索引。 對於分割槽表索引,可以使用alter index xxx rebuild partition yyy的語句,因為分割槽索引的 重建不會使用舊索引,所以可以不加online關鍵字。

  索引壞塊注意以下:

 ---確認索引所屬的表

 select table_owner,table_name from dba_indexes  where owner='&owner'  and index_name='&segment_name';

--如果是分割槽索引,檢視屬於分割槽

select partition_name from dba_extents where file_id=&AFN and &bad_block_id between block_id and block_id + blocks-1;

--確認這個索引是否用於某個約束

select owner,constrint_name,constraint_type,table_name from dba_constraints  where owner='&table_owner' and constraint_name='&index_name';

--如果這個索引是主鍵索引,確認是否有外來鍵指向這個索引

select owner,constraint_name,constraint_type,table_name from dba_constraints where r_owner='&owner' and r_constraint_name='&constraint_name';

   5.2.3恢復資料

       恢復資料就是把其他好的資料塊中的資料全部搶救出來。簡單地說就是把手損資料塊標識成"software corrupt", 然後讓Oracle做全表掃描時跳過這些塊,而不是丟擲異常,從而通過CTAS(create table xx as select ...)方法把資料搶救出來。

      要想讓Oracle做全表掃描時跳過這些塊(前提是先被打上"software corrupt"標記),可以使用兩種方法: 使用dbms_repair包或使用10231事件。

     如果遇到ORA-1578錯誤,說明資料塊已經被標識為"software corrupt"。如果是其他錯誤如ORA-600,就說明損壞的資料塊還沒有被標識為"software corrupt"。

      檢視資料壞快是否被標記為"software corrupt",可以通過DBMS_REPAIR.CHECK_OBJECT方法檢查後查詢REPAIR_TABLE表,如果資料塊已經被標識成"software corrupt",那麼 REPAIR_TABLE 表 marked_corrupt列為true,repair_description 列沒內容。如果資料塊沒有被標識成"software corrupt",REPAIR_TABLE 表 marked_corrupt列為FALSE,repair_description列會提示"mark block software corrupt",也就是需要把資料塊標識為"software corrupt"。

     當資料塊被標識為"software corrupt"後,就可以利用 dbms_repair.skip_corrupt_blocks或者10231事件對segment做一個 標誌,代表掃描該物件時如果遇到"software corrupt"的資料塊可以直接跳過,而不是丟擲ORA-01578錯誤終止,這樣就可以完成對所有好的資料塊的掃描,實現搶救資料。從檢視dba_tables.skip_corrupt欄位可以看出表是否設定了這個標誌。

    ###dbms_repair方法

        設定標誌:exec dbms_repair.skip_corrupt_block(<schema>,<tablename>);         設定完標識後再掃描到資料就不會提示錯誤,而是會在log日誌中記錄一條條目:         table scan:segment file# 6 block# 4 skipping corrupt block file#6 block# 5         清除標誌:exec dbms_repair.skip_corrupt_block(<schema>,<tablename>,flags=dbms_repair.noskip_flag);

      ###使用10231事件

      會話級別設定:alter session set events '10231 trace name context forever,level 10';

       通過初始化引數在例項級別設定:event="10231 trace name context forever,level 10";

5.壞塊恢復例項

參考: 張曉明<<大話Oracle RAC 叢集 高可用 備份與恢復>> http://blog.itpub.net/25472150/viewspace-688629/ http://blog.itpub.net/8494287/viewspace-1357457/ http://www.cnblogs.com/sumsen/archive/2013/01/20/2868740.html