1. 程式人生 > >Oracle - 壞塊修復(一)

Oracle - 壞塊修復(一)

一、概述

本文將介紹如何模擬壞塊,以及出現壞塊該如何修復。實驗分為以下幾個步驟。
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 |
---------------------------------------------------------------------------------------

所以,如果是索引的壞塊,不建議使用rebuild online,一是老的索引在rebuild的過程中仍然存在,sql查詢可能會依然報錯,而刪掉壞的索引,會立刻強迫sql走其它索引或全表,不至於引起sql報錯。二是即使rebuild online完成之後,它雖然讓重建後的索引能夠正常使用,但是壞塊依然存在在老的索引段中,系統並沒有及時回收這個段,強迫症會覺得不舒服。
 

四、總結

1. 壞塊修復的前提是要有完整的備份,所以一定得為生產環境指定備份策略
2. 表的壞塊恢復直接使用rman
3. 索引的壞塊恢復可以使用rman,也可通過刪除索引再重建的方式修復

如果該主庫有dg,那麼主庫有壞塊又該如何修復,dg有壞塊又該如何修復,請看“dg壞塊修復(二