檢查資料庫壞塊並處理
檢測Oracle資料庫壞塊的辦法:
1、使用DBV(DB File Verify)工具;
2、使用RMAN(Recovery Manager)工具;
DBV(DB File Verify)工具:
外部命令,物理介質資料結構完整性檢查;
只能用於資料檔案(offline或online),不支援控制檔案和重做日誌檔案的塊檢查;
也可以驗證備份檔案(rman的copy命令備份或作業系統CP命令備份);
進入碟符,然後執行以下指令碼:
D:\app\Administrator\oradata\orcl>dbv file=ZL9MTLBASE.DBF blocksize=8192;
RMAN(Recovery Manager)工具:
邏輯資料結構完整性檢查;
線上使用Recovery Manager掃描壞塊和備份時,需要資料庫執行在歸檔模式(archive log),否則只能在資料庫未開啟(mount)的情況下進行;
RMAN>backup check logical validate datafile n ;
以上命令可以檢查資料檔案是否包含壞塊,同時並不產生實際的備份輸出。
而且當使用Recovery Manager進行實際的資料庫備份時,同時也就進行了壞塊檢查。
直接使用RMAN的命令:backup validate check logical database;
結合V$DATABASE_BLOCK_CORRUPTION檢視更方便。
1)、rman target / nocatalog
2)、RMAN> spool log to 'd:/dbbak/rmanlog.log';---指定輸出rman日誌檔案
RMAN> run {
allocate channel d1 type disk;
allocate channel d2 type disk;
allocate channel d3 type disk;
allocate channel d4 type disk;
backup validate check logical database;
};
3)、select * from V$DATABASE_BLOCK_CORRUPTION;
4) 、--If V$DATABASE_BLOCK_CORRUPTION contains rows please run this query to find the objects that contains the corrupted blocks:
SELECT e.owner,
e.segment_type,
e.segment_name,
e.partition_name,
c.file#,
greatest(e.block_id, c.block#) corr_start_block#,
least(e.block_id + e.blocks - 1, c.block# + c.blocks - 1) corr_end_block#,
least(e.block_id + e.blocks - 1, c.block# + c.blocks - 1) -
greatest(e.block_id, c.block#) + 1 blocks_corrupted,
null description
FROM dba_extents e, v$database_block_corruption c
WHERE e.file_id = c.file#
AND e.block_id <= c.block# + c.blocks - 1
AND e.block_id + e.blocks - 1 >= c.block#
UNION
SELECT s.owner,
s.segment_type,
s.segment_name,
s.partition_name,
c.file#,
header_block corr_start_block#,
header_block corr_end_block#,
1 blocks_corrupted,
'Segment Header' description
FROM dba_segments s, v$database_block_corruption c
WHERE s.header_file = c.file#
AND s.header_block between c.block# and c.block# + c.blocks - 1
UNION
SELECT null owner,
null segment_type,
null segment_name,
null partition_name,
c.file#,
greatest(f.block_id, c.block#) corr_start_block#,
least(f.block_id + f.blocks - 1, c.block# + c.blocks - 1) corr_end_block#,
least(f.block_id + f.blocks - 1, c.block# + c.blocks - 1) -
greatest(f.block_id, c.block#) + 1 blocks_corrupted,
'Free Block' description
FROM dba_free_space f, v$database_block_corruption c
WHERE f.file_id = c.file#
AND f.block_id <= c.block# + c.blocks - 1
AND f.block_id + f.blocks - 1 >= c.block#
order by file#, corr_start_block#;
5)、
SELECT tablespace_name, segment_type, owner, segment_name
FROM dba_extents
WHERE file_id = &fileid
and &blockid between block_id AND block_id + blocks - 1;
告警日誌中快速識別:
遇到壞塊問題時,資料庫的異常表現通常有:
報告ORA-01578錯誤。
報告ORA-1110錯誤。
報告ORA-00600錯誤。其中,第一個引數為2000-8000,Cache layer 2000 – 4000,Transaction layer 4000 – 6000,Data layer 6000 - 8000。
Trace檔案中出現Corrupt block dba: 0x160c5958 . found。 分析物件失敗。
後臺程序,如DBWR,LGWR出現長時間異常等待,如LGWR wait for redo copy。
修復資料庫壞塊
dbv
你也可以用dbv工具看一下你現在其他的資料檔案有沒有還有壞塊的
dbv file='yourfilename'
恢復方法:
當Oracle資料庫出現壞塊時,Oracle會在警告日誌檔案(alert_SID.log)中記錄壞塊的資訊:
ORA-01578: ORACLE data block corrupted (file # 7, block # )
ORA-01110: data file : '/oracle1/oradata/V920/oradata/V816/users01.dbf'
其中,<AFN>代表壞塊所在資料檔案的絕對檔案號,代表壞塊是資料檔案上的第幾個資料塊
出現這種情況時,應該首先檢查是否是硬體及作業系統上的故障導致Oracle資料庫出現壞塊。在排除了資料庫以外的原因後,再對發生壞塊的資料庫物件進行處理。
1.確定發生壞塊的資料庫物件
SELECT tablespace_name,
segment_type,
owner,
segment_name
FROM dba_extents
WHERE file_id =
AND between block_id AND block_id+blocks-1;
2.決定修復方法
如果發生壞塊的物件是一個索引,那麼可以直接把索引DROP掉後,再根據表裡的記錄進行重建;
如果發生壞塊的表的記錄可以根據其它表的記錄生成的話,那麼可以直接把這個表DROP掉後重建;
如果有資料庫的備份,則恢復資料庫的方法來進行修復;
如果表裡的記錄沒有其它辦法恢復,那麼壞塊上的記錄就丟失了,只能把表中其它資料壞上的記錄取出來,然後對這個表進行重建。
3.用Oracle提供的DBMS_REPAIR包標記出壞塊
exec DBMS_REPAIR.SKIP_CORRUPT_BLOCKS('','');
4.使用Create table as select命令將表中其它塊上的記錄儲存到另一張表上
create table corrupt_table_bak
as
select * from corrupt_table;
5.用DROP TABLE命令刪除有壞塊的表
drop table corrupt_table;
6.用alter table rename命令恢復原來的表
alter table corrupt_table_bak
rename to corrupt_table;
7.如果表上存在索引,則要重建表上的索引
PART2
2014.7.22研究恢復資料庫壞塊:
Oracle呼叫標準C的系統函式,對資料塊進行讀寫操作,因此,壞塊是有可能由以下幾種原因產生:
硬體的I/O錯誤
作業系統的I/O錯誤或緩衝問題
記憶體或paging問題
磁碟修復工具
一個數據檔案的一部分正在被覆蓋
Oracle試圖訪問一個未被格式化的系統塊失敗
資料檔案部分溢位
Oracle或者作業系統的bug
遇到“ORA-01578:ORACLE data block corrupted”錯誤
處理方法:1.rman的recover命令可以在資料庫保持open狀態下只恢復受損的資料塊
2.如果沒有備份,萬不得已之下也可以採用DBMS_REPAIR包的儲存過程將受損壞塊隔離,同時儘可能地挽救部分資料。
rman backup命令也是檢查壞資料塊的好工具 一旦讀取ORA-19566 即可有問題
此時可用backup validate tablespace user觀察詳細的資訊,可檢視到壞塊數與跟蹤檔案
grep‘corrupt’/u01/app/oracle/diag/rdbms/br/br/trace/**.trc
恢復資料塊:rman》recover datafile 5 block 203;
批量恢復受損的資料塊:recover corruption list;
資料塊壞塊一號壞塊,需要做:
run{
sql 'alter database datafile 5 offline';
restore datafile 5;
recover datafile 5;
sql'alter database datafile 5 online'
}
使用exp/imp恢復
在這種情況下肯定會造成資料的丟失,在這種情況下應採取將資料匯出然後重建表再進行匯入的方法,來儘量恢復損壞資料塊中的資料,但是在有壞塊的情況下是不允許匯出的,如下命令:Exp test/test file=t.dmp tables=t;
匯出命令在執行中會報ORA-01578錯誤,在這錯誤提示中會提示那個檔案號的檔案以及這個檔案中的哪個塊被損壞,如:ORA—01578:ORACLE 資料塊損壞(檔案號 4,塊號 35)
針對以上的提示首先查詢那些物件被損壞:
Select tablespace_name,segment_type,owner,segment_name From dba_extents Where file_id=4 and 35 between block_id and block_id+blocks-1;
如果被損壞的塊是索引,通常可以通過索引重建來解決,如果損壞的是資料(segment_type為table),那麼通過設定如下內部事件使得Exp操作跳過壞塊。
Alter session set events=’10231 trace name context forever,level 10’;
然後重新執行匯出命令,匯出相關的表,然後執行Drop Table命令刪除相關表,之後重建表最後匯入資料。
使用DBMS_REPAIR恢復
用DBMS_REPAIR當然也會丟失資料。這裡不做詳細的介紹,有興趣的可以檢視oracle的線上文
3、使用dbms_repair包進行壞塊處理
1)首先建立repair_table,用於存放dbms_repair.check_object檢測出來的壞塊資訊
SQL> declare
2begin
3dbms_repair.admin_tables
4(table_name => 'REPAIR_TABLE',--表名
5table_type => dbms_repair.repair_table,
6action => dbms_repair.create_action,
7tablespace => 'USERS');--用於指定該表存放的表空間
8end;
9/
PL/SQL 過程已成功完成。
SQL> col owner format a10
SQL> col object_name format a20
SQL> col object_type format a20
SQL> select owner, object_name, object_type
2from dba_objects
3where object_name like '%REPAIR_TABLE';
OWNEROBJECT_NAMEOBJECT_TYPE
---------- -------------------- --------------------
SYSREPAIR_TABLETABLE
SYSDBA_REPAIR_TABLEVIEW
Oracle自動建立了一個DBA_REPAIR_TABLE檢視。
2)使用dbms_repair.check_object進行壞塊檢測
SQL> set serveroutput on size 100000;
SQL> declare
2rpr_count int;
3begin
4rpr_count := 0;
5dbms_repair.check_object(
6schema_name => 'SYS',--指定物件模式,也就是物件的所有者
7object_name => 'TEST',--指定物件名,也就是表名
8repair_table_name => 'REPAIR_TABLE',
9corrupt_count => rpr_count);
10dbms_output.put_line('repair block count: '
11||to_char(rpr_count));
12end;
13/
repair block count: 4
PL/SQL 過程已成功完成。
SQL> select object_name, block_id, corrupt_type, marked_corrupt,
2corrupt_description, repair_description
3from repair_table;
OBJECT_NAMEBLOCK_ID CORRUPT_TYPE MARKED_COR
-------------------- ---------- ------------ ----------
CORRUPT_DESCRIPTION
-------------------------------------------------------------------------------
REPAIR_DESCRIPTION
-------------------------------------------------------------------------------
TEST196148 TRUE
mark block software corrupt
TEST206148 TRUE
mark block software corrupt
TEST236148 TRUE
mark block software corrupt
TEST316148 TRUE
mark block software corrupt
通過執行dbms_repair.check_object,將壞塊資訊存放到了repair_table表中,其中有個欄位marked_corrupt,用於標識該塊是否被標識為壞塊,當被標識為true時,即該塊被標識為壞塊。其中這一步跟oracle文件中的描述有點進入,根據oracle文件,當執行完dbms_repair.check_object時,並不會進行壞塊標識,也就是marked_corrupt列的值應該為false,而只有當執行dbms_repair.fix_corrupt_blocks過程後才會進行壞塊標識。
3)使用dbms_repair.fix_corrupt_blocks進行壞塊標識
SQL> declare
2fix_block_count int;
3begin
4fix_block_count := 0;
5dbms_repair.fix_corrupt_blocks (
6schema_name => 'SYS',
7object_name => 'TEST',
8object_type => dbms_repair.table_object,
9repair_table_name => 'REPAIR_TABLE',
10fix_count => fix_block_count);
11dbms_output.put_line('fix blocks count: ' ||
12to_char(fix_block_count));
13end;
14/
fix blocks count: 0
PL/SQL 過程已成功完成。
我們可以見到到fix blocks count=0,即在上一步進行check_object時已經進行了壞塊標識了,這一步其實可以省略。(不過沒有測試過!)