一、概述
本文將介紹如何模擬壞塊,以及出現壞塊該如何修復。實驗分為以下幾個步驟。
1. 表出現壞塊
2. 索引出現壞塊
二、環境准備
本實驗都是在oracle 11G歸檔模式下進行。
1. 准備相關表
create tablespace tbs01 datafile '/u01/app/oracle/oradata/orcltest/tbs01.dbf' size 100m;
create table scott.t01 tablespace tbs01 as select * from dba_objects where rownum<=100;
create index scott.idx_t01 on scott.t01(object_id) tablespace tbs01;
select rowid, dbms_rowid.rowid_relative_fno(rowid) file_id, dbms_rowid.rowid_block_number(rowid) block_id from scott.t01;
ROWID FILE_ID BLOCK_ID ------------------ ---------- ---------- AAAVpMAAGAAAACDAAA 6 131 AAAVpMAAGAAAACDAAB 6 131 AAAVpMAAGAAAACDAAC 6 131 AAAVpMAAGAAAACDAAD 6 131 AAAVpMAAGAAAACDAAE 6 131 AAAVpMAAGAAAACDAAF 6 131 AAAVpMAAGAAAACDAAG 6 131 ...
select segment_name, segment_type, file_id, block_id, blocks from dba_extents where segment_name='IDX_T01';
SEGMENT_NAME SEGMENT_TYPE FILE_ID BLOCK_ID BLOCKS --------------- ------------------ ---------- ---------- ---------- IDX_T01 INDEX 6 136 8
2. 全庫備份
RMAN> backup database; // 全庫備份
RMAN> list backup; // 查看備份
List of Backup Sets =================== BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ --------------- 19 Full 1.08G DISK 00:01:59 12-MAR-20 BP Key: 19 Status: AVAILABLE Compressed: NO Tag: TAG20200312T150629 Piece Name: /home/oracle/backupdir/ORCLTEST_2750922031_40_1_20200312_1034867190.bkp List of Datafiles in backup set 19 File LV Type Ckp SCN Ckp Time Name ---- -- ---- ---------- --------- ---- 1 Full 1148218 12-MAR-20 /u01/app/oracle/oradata/orcltest/system01.dbf 2 Full 1148218 12-MAR-20 /u01/app/oracle/oradata/orcltest/sysaux01.dbf 3 Full 1148218 12-MAR-20 /u01/app/oracle/oradata/orcltest/undotbs01.dbf 4 Full 1148218 12-MAR-20 /u01/app/oracle/oradata/orcltest/users01.dbf 5 Full 1148218 12-MAR-20 /u01/app/oracle/oradata/orcltest/example01.dbf 6 Full 1148218 12-MAR-20 /u01/app/oracle/oradata/orcltest/tbs01.dbf
三、正式實驗
1. 表出現壞塊
1.1 模擬壞塊
RMAN> blockrecover datafile 6 block 131 clear; // 將131數據塊清空,即相當於產生了壞塊
SQL> select * from scott.t01; // 對表進行查詢
select * from scott.t01 * ERROR at line 1: ORA-01578: ORACLE data block corrupted (file # 6, block # 131) ORA-01110: data file 6: '/u01/app/oracle/oradata/orcltest/tbs01.dbf'
1.2 檢測壞塊
檢測壞塊可以使用以下兩種方式
a. 使用rman檢測壞塊
RMAN> backup check logical validate datafile 6;
上面rman檢測到的壞塊具體信息可以通過v$database_block_corruption查看
b. 使用oracle安裝時自帶的dbv工具
[oracle@orasingle ~]$ dbv file='/u01/app/oracle/oradata/orcltest/tbs01.dbf'
但是通過dbv工具並不能直觀判斷到底是什么類型數據塊出現了壞塊
1.3 壞塊修復
RMAN> backup check logical validate datafile 6; // 檢測數據文件的壞塊
RMAN> blockrecover corruption list; // 自動修復檢測出的壞塊,該命令執行成功的前提是有完整的rman備份
SQL> select * from scott.t01; // 再查詢就沒有錯誤了
2. 索引出現壞塊
查看下面sql的執行計划
SQL> select * from scott.t01 where object_id=100;
SQL> select * from table(dbms_xplan.display_cursor(null,null,'TYPICAL PEEKED_BINDS'));
--------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| T01 | 1 | 207 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_T01 | 1 | | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------
2.1 模擬壞塊
RMAN> blockrecover datafile 6 block 139 clear; // 將139索引塊清空,即相當於索引產生了壞塊
可能大家會有疑惑,該索引的塊的block_id是136,你為什么要清空139呢?這就涉及到段的管理方式了,136-138這三個塊依次是一級位圖塊,二級位圖塊,段頭。真正存放數據的是從139開始。可以將塊dump出來看看塊的類型。
SQL> select * from scott.t01 where object_id=100; // 再來查詢該sql
select * from scott.t01 where object_id=100 * ERROR at line 1: ORA-01578: ORACLE data block corrupted (file # 6, block # 139) ORA-01110: data file 6: '/u01/app/oracle/oradata/orcltest/tbs01.dbf'
在這里我們可以看到,這里的報錯與前面表上有壞塊的報錯一模一樣,因此當我們查詢一張表出現這類報錯的時候,可能並不是表有壞塊,而可能是這張表上的索引有壞塊。
2.2 檢查壞塊
RMAN> backup check logical validate datafile 6;
同樣也可以通過下面的sql確定壞塊的段類型。
select owner, segment_name, segment_type from dba_extents where 139 between block_id and block_id+blocks-1 and file_id=6;
2.3 修復壞塊
索引的壞塊修復有兩種方式,第一種就是跟表一樣,直接修復數據文件
RMAN> backup check logical validate datafile 6; // 檢測數據文件的壞塊
RMAN> blockrecover corruption list; // 自動修復檢測出的壞塊
第二種方式就是將索引直接刪了重建,原理就是如果索引被刪除了,這個段就會被系統回收,該段上所有的塊都會被初始化,也就不存在什么壞塊了。
select dbms_metadata.get_ddl('INDEX', 'IDX_T01', 'SCOTT') from dual; // 通過該sql查索引的創建信息
drop index scott.idx_t01; // 刪除索引
CREATE INDEX "SCOTT"."IDX_T01" ON "SCOTT"."T01" ("OBJECT_ID") TABLESPACE "TBS01" online; // 創建索引
2.4 試試rebuild online
可能你會問,為什么索引刪了重建,直接rebuild不更好嗎?那么我們再試試索引有壞塊了,rebuild是個什么效果
RMAN> blockrecover datafile 6 block 139 clear;
RMAN> backup check logical validate datafile 6;
List of Datafiles ================= File Status Marked Corrupt Empty Blocks Blocks Examined High SCN ---- ------ -------------- ------------ --------------- ---------- 6 FAILED 0 12656 12800 1234071 File Name: /u01/app/oracle/oradata/orcltest/tbs01.dbf Block Type Blocks Failing Blocks Processed ---------- -------------- ---------------- Data 0 2 Index 1 3 Other 0 139
使用rebuild命令重建索引(注意要使用online的方式,如果不加online就是通過原索引重建索引,會直接報錯。)
alter index scott.idx_t01 rebuild online;
RMAN> backup check logical validate datafile 6; // 可以看到壞塊依然存在,這個只是系統還沒有暫時回收老的索引段而已。可以忽略。
select * from scott.t01 where object_id=100; // 查詢沒有問題,索引也有效
select * from table(dbms_xplan.display_cursor(null,null,'TYPICAL PEEKED_BINDS'));
--------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| T01 | 1 | 207 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_T01 | 1 | | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------
所以,如果是索引的壞塊,可以對索引直接重建來消除壞塊。
四、總結
1. 壞塊修復的前提是要有完整的備份,所以一定得為生產環境指定備份策略
2. 表的壞塊恢復直接使用rman
3. 索引的壞塊恢復可以使用rman,也可通過刪除索引再重建的方式修復
如果該主庫有dg,那么主庫有壞塊又該如何修復,dg有壞塊又該如何修復,請看“dg壞塊修復(二)”