天天看點

資料庫診斷之壞塊診斷及修複

-- 診斷資料庫

1.檢視故障

list failure [all | critical | high | low | closed | failnum[,failnum,...]]

[ exclude failure failnum[,failnum,...]]

[ detail]

删除資料檔案6

[oracle@dbserver ~]$ rm -fr /u01/app/oracle/oradata/orcl/ts_inventory01.dbf

列出故障,預設顯示優先級為high的故障。

rman> list failure;

列出故障明細

rman> list failure detail;

2.故障修複建議

advise failure

注意,advise failure 必須在同一個視窗中緊跟 list failure 才能正常使用。

rman> advise failure;

上面指令系統會給出修複故障的腳本,檢視腳本内容如下:

$ more /u01/app/oracle/diag/rdbms/orcl/orcl/hm/reco_1651608170.hm

3.修複故障

repair failure

[ using advise option integer ]

[ noprompt | review]

注意,repair failuer 必須在同一視窗中緊跟 advise failure 後才能正常使用。

修複預覽

rman> repair failure preview;

修複故障,noprompt 表示不提示直接修複,不帶将會出現修複提示。

rman> repair failure noprompt;

4.修改故障優先級和關閉故障 change failure

修改上面原來high的故障的優先級到low

rman> change failure 402 priority low;

再次查詢将查不到low的故障

但可以指定查詢low級别的故障

rman> list failure low;

rman> list failure all;

關閉故障

rman> change failure 402 closed;

5.故障恢複相關視圖

v$ir_failure: 包含所有檢測到的故障,包含已經關閉的故障。

v$ir_manual_checklist: 相關故障的手動修複建議

v$ir_repair: 相關故障的自動修複步驟

v$ir_failure_set: 存放故障id和其修複建議id的關聯

6.主動監控資料庫

使用em健康監控或rman指令 validate database

rman> validate database; --11g才開始提供的指令

11g之前使用dbv工具進行資料庫檔案校驗(支援離線校驗):

$ dbv file=/u01/app/oracle/oradata/orcl/ts_inventory01.dbf

11g之前還可以使用 dbms_repair 包中相關的函數進行壞塊的處理

7.關于資料塊校驗的幾個參數

db_ultra_safe: 整合了db_block_checking,db_block_checksum,db_lost_write_protect三個參數,屬于11g的新參數。

db_block_checking: 啟動對資料庫塊的檢查,預設為false,即使關閉也會強制檢查system表空間的資料塊。

db_block_checksum: 修改塊資料時加入并且驗證塊的校驗位,預設為typical

db_lost_write_protect: 在data guard中保護資料成功寫入實體備庫,預設為typical

8.塊媒體恢複

恢複條件:

①開啟歸檔

②存在全備或0級備份

③存在有效的閃回日志

v$database_block_corruption: 存放資料中所有壞塊資訊

資料庫存在壞塊時,預設是不允許進行備份的,是以需要經常檢查備份的有效性。

可以允許跳過壞塊進行備份,同時把壞塊資訊寫入 v$database_block_corruption中:

rman> run {

set maxcorrupt for datafile 6 to 1000;

backup datafile 6;

}

修複一個塊:

recover datafile 6 block 131;

修複多個塊:

recovery datafile 2 block 43

datafile 2 block 70

datafile 6 block 110;

修複所有壞塊:

recover corruption list;

修複好的塊将不再出現在 v$database_block_corruption.

9.檢視診斷知識庫(11g開始才推出adr)

使用 adrci 工具

$ adrci

adrci> help --檢視adrci的幫助資訊

adrci> show incident; --檢視所有的事件資訊

adrci> show alert; --檢視所有的報警資訊

也可以通過v$diag_info檢視診斷資訊

sql> select*from v$diag_info;

11g中診斷資訊相關目錄參數不能修改,統一設定到adr_home/ 目錄下

10.健康監控

視圖v$hm_check列出所有健康監控的内容

健康檢查可以使用em(em中助手中心裡的檢查器)

也可以調用dbms_hm.run_check執行健康檢查

tab$ 表示資料庫中的所有基表

sql> exec dbms_hm.run_check('dictionary integrity check','mycheck',0,'table_name=tab$'); 

sql> set long 20000

sql> select dbms_hm.get_run_report('mycheck') from dual;

在adrci中檢視健康檢查

adrci> show home

adrci> set home diag/rdbms/orcl/orcl

adrci> create report hm_run mycheck

adrci> show report hm_run mycheck

-- 壞塊修複示例 --

-- 用内部事件來屏蔽全表掃描的時候忽略壞塊。

alter system set events='10231 trace name context for ever,level 10'

-- 給定一個表空間,并在此表空間下建立維修表

exec dbms_repair.admin_tables(table_name => 'repair_table',table_type => dbms_repair.repair_table,action => dbms_repair.create_action,tablespace => 'users');

-- 對指定的<schema>.<object>檢查并确認其中壞塊(如果同時指定 partition_name 也可以進行分區級别檢查):

set serveroutput on 

var num_corrupt number;

exec :num_corrupt :=0;

exec dbms_repair.check_object(schema_name => 'sys',object_name => 'impdp_stats',repair_table_name => 'repair_table',corrupt_count => :num_corrupt);

exec dbms_output.put_line('number corrupt: ' || to_char(:num_corrupt));

-- 對檢查出的壞塊,可選擇性地進行标記:

select block_id, corrupt_type, corrupt_description from repair_table;

-- rem mark the identified blocks as corrupted ( soft corrupt - reference note 1496934.1 )

var num_fix number;

exec :num_fix := 0;

exec dbms_repair.fix_corrupt_blocks(schema_name => 'sys',object_name => 'impdp_stats',object_type => dbms_repair.table_object,repair_table_name => 'repair_table',fix_count => :num_fix);

exec dbms_output.put_line('num fix: ' || to_char(num_fix));

-- 在将來進行dml操作時,對壞塊進行跳過處理:

exec dbms_repair.skip_corrupt_blocks (schema_name => '&schema_name',object_name => '&object_name',object_type => dbms_repair.table_object,flags => dbms_repair.skip_flag);

-- 注意:

使用dbms_repair通路壞塊後,index scan可能會出現報錯,碰到這類報錯,你需要重建這些索引。如果是唯一索引,那麼相同資料的重新插入可能會報ora-1錯誤。

如果在 dbms_repair.skip_flag 已經啟用後,希望将跳塊标記清除以重新通路壞塊,可以在執行dbms_repair.skip_corrupt_blocks時,使用dbms_repair.noskip_flag進行參數設定。

使用dbms_repair.skip_corrupt_blocks來跳塊僅能針對出現ora-1578報錯的那些壞塊情況。如果是針對其它類型壞塊,就需要額外執行admin_tables, check_object 和fix_corrupt_blocks來對壞塊進行标記處理。

在執行過skip_corrupt_blocks後,如果需要将表中的壞塊進行清理,可以對表使用”alter table <name> move”,而不是重建或truncate掉它。然後使用dbms_repair.noskip_flag去除掉跳塊标記即可。注意,壞塊中的資料會被丢失掉。

-----------------------------------------------------------------------------

-- 壞塊問題

-- db file verify(dbv) 工具

-- 外部指令,實體媒體資料結構完整性檢查;

-- 隻能用于資料檔案(offline或online),不支援控制檔案和重做日志檔案的塊檢查;

-- 也可以驗證備份檔案(rman的copy指令備份或作業系統cp指令備份);

-- dbv file=data01.dbf blocksize=8192;

-- 解決壞塊過程

找出資料檔案上的表、分析出出現壞塊的表、找出所有的壞塊:

找出檔案編号:

select * from dba_data_files t where t.file_name = '/u01/../../.dbf';

找出檔案上的表:

select distinct t.segment_name , t.segment_type  from dba_extents t where t.file_id = '12' order by t.segment_name, t.segment_type;

--使用select count(1) from tablename的辦法,找出哪些表上有壞塊。

sql> select count(1) from schema.table;

error at line 1:

ora-01578: oracle data block corrupted (file # 12, block # 608129)

ora-01110: data file 12: '/u01/../../.dbf'

從上面查詢可知表tablename上有壞塊,但可能不止一個壞塊,是以我使用dbv找出這個表上所有壞塊。辦法是,找出表的segment_id:

select s.ts#, t.header_file, t.header_block , t.owner, t.* from dba_segments t

left join v$tablespace s

on t.tablespace_name = s.name 

where t.segment_name = 'table_name';

6.5.1118066

在伺服器上,執行dbv工具:

dbv logfile=/home/oracle/dbv_lkpspf_.log userid=ahern/oracle segment_id=6.5.1118066 -- 分析指令執行的結果

-- 1、使用rman修複壞塊,但因為歸檔丢失,無法恢複。

rman> recover datafile 18 block 58630;

-- 2、使用 sys.dbms_repair修複:fix_corrupt_blocks修複失敗、skip_corrupt_blocks忽略壞塊、導出可以用資料、删除壞塊的表。

--建repaire表:repair_table

sql> begin

dbms_repair.admin_tables(

table_type=>dbms_repair.repair_table,

action=>dbms_repair.create_action,

tablespace=>'users'

);

end;

/

-- 檢查壞塊:

sql> declare

cc number;

begin

dbms_repair.check_object(

  schema_name=>'lkpspf',

  object_name=>'tb_orders',

  object_type=>dbms_repair.table_object,

  repair_table_name=>'repair_table',

  corrupt_count=>cc

dbms_output.put_line(cc);

--查詢壞塊:

sql> col repair_description for a50

sql> select block_id, repair_description from repair_table; 

608129 mark block software corrupt 

608193 mark block software corrupt  

-- 與dbv分析結果相同。

--使用 fix_corrupt_blocks 恢複壞塊,但沒有成功。

sql> declare 

  dbms_repair.fix_corrupt_blocks(

    'lkpspf',

    'tb_orders',

    fix_count=>cc

  );

  dbms_output.put_line(cc);

--隻能跳過壞塊,使用skip_corrupt_blocks過程。

  cc number;

  begin

  dbms_repair.skip_corrupt_blocks(

    schema_name=>'lkpspf',

    object_name=>'tb_orders'

--此時,存在壞塊的表可以使用,但壞塊中記錄丢失了。

select count(1) from lkpspf.tb_orders;

66545839

--壞塊還在資料檔案中,仍就不能使用rman備份。

rman> backup datafile '/../../.dbf';

--此時,需要把存在壞塊的表中的資料使用ctas方式遷移到其他表中。然後删除有壞塊的表。再次執行rman備份:備份成功。

-- 附壞塊查詢 sql

rman>backup check logical validate datafile n ; -- 檢查資料檔案是否包含壞塊,同時并不産生實際的備份輸出

-- 也可以直接使用rman的指令:backup validate check logical database;

rman target / nocatalog

rman> spool log to '/u01/../dbbak/rmanlog.log'; -- 指定輸出rman日志檔案

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;

};

-- 結合v$database_block_corruption視圖更友善

select * from v$database_block_corruption;

-- --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,

       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

select null owner,

       null segment_type,

       null segment_name,

       null partition_name,

       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#;

-- 執行下面語句的結果來自于上面的查詢

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;