首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 冲浪宝典 > 网络资源 > 關于數據壞塊處理
【标  题】:關于數據壞塊處理
【关键字】:
【来  源】:http://www.cublog.cn/u/20571/showart.php?id=139670

關于數據壞塊處理

  有關數據壞塊﹐昨天一朋友碰到過﹐通過遠程支持總算處理好了。沒出什么意外。在網上很多的關于ORA-01578的文章﹐其中就有講到過文件系統格式空間的限制導致。我所知道的windows的FAT,FAT32,Linux的ext2就有2GB的限制﹐windows的ntfs和Linux的Ext3就沒有這種限制。Linux下面的情況碰到過一次也是朋友的DB﹐因為沒有專職的DBA來管理﹐所有的data file全部設為自己擴展﹐并且沒有作限制,最終超過2GB﹐因為是在noarchivelog模式下﹐出錯后又重啟了機器,最后啟動DB時只好drop datafile 來啟動﹐丟了半天的資料。
所在在DB創建時﹐一定要注意文件系統﹐和文件是否自動擴展﹐最大size為多大。

查核文件是否自動擴展
select file_name,AUTOEXTENSIBLE,MAXBYTES/1024/1024 from dba_data_files;

允許文件自動擴展如
alter database datafile '/app/oracle/oradata/oms/system01.dbf'autoextend on  maxsize 400m;

限制文件自動擴展如
alter database datafile '/app/oracle/oradata/oms/system01.dbf'  autoextend off;

如果壞塊是針對某個數據文件里面的壞塊.
1) 用dbv來檢測數據文件。
2) select owner,segment_name,segment_type from dba_extents where file_id='文件號'  and 壞塊號 between block_id and (block_id+blocks-1)
如果查出來的segment_type為index,則可以刪掉索相重建。
如果查出來的segment_type為table,則要具體對待。
資料收集中﹐整理好后再貼上來。

我也懶得寫了﹐把網上的抄下來﹐有些有用有些東東可能有變化﹐或有更多的方法處理。
如表空間擴展的問題﹐9i的話就有一個可恢復表空間的性能﹐空間不夠可以先停下來擴展空間后再繼續先前的事務來處理。9i又新增加了block  error recover的功能。

------------------中国交管信息技术商务网-----------------

   在使用ORACLE的過程中,我們會經常遇到一些ORACLE產生的錯誤,對於初學者而言,這些錯誤可能有點模糊,而且可能一時不知怎麼去處理產生的這 些錯誤,本人就使用中出現比較頻繁的錯誤代碼一一做出分析,希望能夠幫助你找到一個合理解決這些錯誤的方法,同時也希望你能夠提出你的不同看法。畢竟作為 一種交流的手段,個人意見難免過於偏頗,而且也必定存在著不足,出錯之處在所難免。寫這篇文章的目的就是想通過相互之間的交流共同促進,共同進步。

  ORA-01650: unable to extend rollback segment NAME by NUM intablespace NAME

  產生原因:上述ORACLE錯誤為回滾段表空間不足引起的,這也是ORACLE資料管理員最常見的ORACLE錯誤資訊。當用戶在做一個非常龐大的資料操作導致現有回滾段的不足,使可分配用的回滾段表空間已滿,無法再進行分配,就會出現上述的錯誤。

  解決方法:使用“ALTER TABLESPACE tablespace_name ADD DATAFILE filename SIZE size_of_file”命令向指定的資料增加表空間,根據具體情況可以增加一個或多個表空間。當然這與還與你主機上的裸盤設備有關,如果你主機的裸盤 設備已經沒有多餘的使用空間,建議你不要輕意增加回滾段表空間的大小,可使用下列語句先查詢一下剩餘的tablespace空間有多少:

  select user_name,sql_text from V$open_cursor where user_name='';

  如果多餘的空間比較多,就可以適當追加一個大的回滾段給表空間使用,從而避免上述的錯誤。你也可以用以下語句來檢測一下rollback segment的競爭狀況:

  Select class, count

  from V$waitstat

  where calss in('system undo header', 'system undo block', 'undo header', 'undo block');

  和

  select sum(value)

  from V$sysstat

  where name in ('db_block_gets', 'consistents gets');

  如果任何一個class in count/sum(value)大於1%,就應該考慮增加rollback segment

  相應的英文如下:

  Cause: Failed to allocate extent from the rollback segment in tablespace.

  Action: Use the ALTER TABLESPACE ADD DATAFILE statement to add one or more files to the specified tablespace.

  ORA-01652: unable to extend temp segment by num in tablespace name.

  產生原因:Oracle臨時段表空間不足,因為Oracle總是儘量分配連續空間,一但沒有足夠的可分配空間或者分配不連續就會出現上述的現象。

  解決方法:我們知道由於Oracle將表空間作為邏輯結構——單元,而表空間的物理結構是資料文 件,資料檔案在磁片上物理地創建,表空間的所有物件也存在於磁片上,為了給表空間增加空間,就必須增加資料檔案。先查看一下指定表空間的可用空間,使用視 SYS.DBA_FREE_SPACE,視圖中每條記錄代表可用空間的碎片大小:

  SQL>select file_id, block_id, blocks, bytes

  from sys.dba_free_space

  where tablespace_name='';

  返回的資訊可初步確定可用空間的最大塊,看一下它是否小於錯誤資訊中提到的尺寸,再查看一下缺省的表空間參數:

  SQL>SELECT INITIAL_EXTENT, NEXT_EXTENT, MIN_EXTENTS, PCT_INCREASE

  FROM SYS.DBA_TABLESPACES

  WHERE TABLESPACE_NAME=name;

  通過下面的SQL命令修改臨時段表空間的缺省存儲值:

  SQL>ALTER TABLESPACE name DEFAULT STORAGE (INITIAL XXX NEXT YYY);

  適當增大缺省值的大小有可能解決出現的錯誤問題,也可以通過修改用戶的臨時表空間大小來解決這個問題:

  SQL>ALTER USER username TEMPORARY TABLESPACE new_tablespace_name;

  使用ALTER TABLESPACE命令,一但完成,所增加的空間就可使用,無需退出資料庫或使表空間脫機,但要注意,一旦添加了資料檔案,就不能再刪除它,若要刪除,就要刪除表空間。

  一個報錯例子如下:

  ORA-1652:unable to extend temp segment by 207381 in tablespace TEMPSPACE

  相應的英文如下:

  Cause: Failed to allocate extent for temp segment in tablespace

  Action: Use the ALTER TABLESPACE ADD DATAFILE statement to add one or more files to the specified tablespace or create the object in another tablespace.

  ORA-01578: Oracle data block corrupted(file # num, block # num)

  產生原因:Oracle訪問一個資料塊時,由於

  1. 硬體的I/O錯誤;

  2. 作業系統的I/O錯誤或緩衝問題;

  3. 記憶體或paging問題;

  4. Oracle試圖訪問一個未被格式化的系統塊失敗;

  5. 資料檔案部分溢出等上述幾種情況的一種引起了邏輯壞塊或者物理壞塊,這時就會報ORA-01578的錯誤。

  解決方法:由於Oracle只有在訪問到有問題的資料檔案時才會報錯,所以報錯的時間有可能會比實際出錯的時間要晚,如果ORA-01578出錯資訊提示資料壞塊指向的是用戶自己的資料檔案,則用以下方法來解決:

  如果通過下面的SQL語句查出的壞塊出現有索引上,則只需重建索引即可。

  SQL>select owner, segmen20059131005116296.htm, segment_type

  from dba_extents

  where file_id= and between block_id and block_id+blocks-1;

  如果壞塊出現在表上,先用以下語句分析是否為永久性壞塊(建議多執行一兩次,有助於鑒別資料壞塊是永久性的(硬碟上的物理壞塊)還是隨機性的(記憶體或硬體錯誤引起)):

  SQL>Analyze table validate structure cascade;

  執行該命令後,可能會出現以下的結果:

  ORA-01578:與原先錯誤資訊有相同的參數,為永久性的物理或邏輯壞塊;與原先錯誤資訊有不同的參數,可能與記憶體,page spaceI/O設備有關。

  如果用戶有此表的最新備份,那麼最好是用此備份來恢復此表,或者使用event 10231來取出壞塊以外的資料:

  1. 先關閉資料庫

  2. 編輯init.ora文件,加入:event="10231 trace name context forever, level 10"

  3. startup restrict

  4. 創建一個臨時表:SQL>create table errortemp as select * from error;(error是壞表的表名)

  5. eventinit.ora檔中刪掉並重起資料庫

  6. rename壞表,把臨時表rename成壞表的表名

  7. 創建表上的INDEX

  如果ORA-01578出錯資訊提示資料壞塊指向的是資料字典或者是回滾段的話,你應該立即與ORACLE公司聯繫,共同商量一個好的解決辦法。

  這裏所講的解決方法只是比較常見的一種,一些更為具體的解決辦法可以查看一下ORACLE的故障解決手冊,那裏面有浞及使用ROWID方法來取出壞塊以外的資料的方法,這裏就不介紹了。

  相應的英文如下:

  Cause: The given data block was corrupted,probably due to program errors

  Action: Try to restore the segment containing the given data block,This may involve dropping the segment and recreating it,If there is a trace file,report the messages recorded in it to customer support.

  ORA-01628: max # of extents num reached for rollback segment num

  產生原因:這種錯誤通常為一個回滾段和一個表空間已經達到MAXEXTENTS參數設置的極限。要注意的是這個MAXEXTENTS不是該回滾段或表空間的硬體極限,硬體極限取決於資料庫創建時在init.ora檔中指定的DB_BLOCK_SIZE參數的值。

  解決方法:使用SQL命令ALTER TABLESPACE…STORAGE(MAXEXTENTS XXXX)來增加MAXEXTENTS,其中“XXXX”值必須大於錯誤資訊中所指的數值,但不能大於LARGEST MAXEXTENT的值,如果已經達到了LARGEST MAXEXTENT VALUE,解決的辦法就是重新創建較大的範圍尺寸,使用帶有選項COMPRESS=YExport工具導出表,如果表空間有可用空間,先給表做一個備 份,用alter tablespace tablespace_name更改其名字,然後再裝載表回資料庫。

  查看其錯誤出現的地方,如果出現在回滾段或索引上,那麼必須將其刪除並重建,如果出現在臨時表空間,修改臨時表空間的存儲欄位,便可解決這個問題。

  一個報錯例子如下:

  ORA-1628: max # extents 50 reached for rollback segment RBS_1

  相應的英文如下:

  Cause: An attempt was made to extend a rollback segment that already has reached its maximum size or space could not be allocated in the data dictionary to contain the definition of the object.

  Action: If possible, increase the value of either the MAXEXTENTS or PCTINCREASE initialization parameters or find the data dictionary table lacking space and alter the storage parameters, as described in the Oracle8 Server Administrator’s Guide.

  ORA-00600: internal error code,arguments: [num], [?], [?], [?], [?]

  產生原因:這種錯誤通常為Oracle的內部錯誤,只對OSSOracle開發有用。ORA- 600的錯誤經常伴隨跟蹤檔的狀態轉儲(系統狀態和進程狀態),系統狀態存儲將包括ORACLE RDBMS持有的當前物件的資訊,進程狀態轉儲則將顯示特殊進程持有的物件,當進程符合了某錯誤條件時,經常是由於一些資訊取自它持有的一個塊,如果我們 知道這些錯誤進程持有的塊,就容易跟蹤問題的來源。

  解決方法:一般來說出現這個錯誤我們本身是無法解決的,只有從提高系統本身各方面來解決這個內部問 題,如增加硬體設備、調整系統性能、使用OPS(當然OPS從某種意義上說並不是一種好的解決方式)等。ORA-600錯誤的第一個變數用於標記代碼中錯 誤的位置(代碼中的每個部分的第一變數都不一樣),從第二個到第五個變數顯示附加資訊,告訴OSS代碼在哪里出現了錯誤。

  一個報錯例子如下:

  ORA-00600: internal error code, arguments: [1237], [], [], [], [], [], [], []

  相應的英文如下:

  Cause: This is a catchall internal error message for Oracle program exceptions.It indicates that a process has met a low-level,unexpected condition.Various causes of this message include:

  Time-outs(超時)

  File corruption(文件太老)

  Failed data checks in memory(記憶體檢索失敗)

  Hardware, memory, or I/O errors(硬體、記憶體或者磁片錯誤)

  Incorrectly restored files(錯誤的重建檔)

  ORA-03113:end-of-file on communication channel

  產生原因:通訊不正常結束,從而導致通訊通道終止。

  解決方法:

  1. 檢查是否有服進程不正常死機,可從alert.log得知

  2. 檢查sql*Net Driver是否連接到ORACLE可執行程式

  3. 檢查伺服器網路是否正常,如網路不通或不穩定等

  4. 檢查同一個網上是否有兩個同樣名字的節點

  5. 檢查同一個網上是否有重複的IP位址

  相應的英文如下:

  Cause: An unexpected end-of-file was processed on the communication channel. The problem could not be handled by the Net8,two task,software. This message could occur if the shadow two-task process associated with a Net8 connect has terminated abnormally, or if there is a physical failure of the interprocess communication vehicle,that is,the network or server machine went down.

  Action: If this message occurs during a commection attempt, check the setup files for the appropriate Net8 driver and confirm Net8 software is correctly installed on the server. If the message occurs after a connection is well established, and the error is not due to a physical failure, check if a trace file was generated on the server at failure time. Existence of a trace file may suggest an Oracle internal error that requires the assistance of customer support.

  ORA-00942: table or view does not exist

  產生原因:這是由於裝載的表或視圖不存在,多半是CATEXP.SQL還沒有運行,無法執行Export視圖,如果CATEXP.SQL已經運行,則可能是版本錯誤。

  解決方法:因為ImportExport共用的一些視圖是通過運行CATEXP.SQL來裝載的 (它們具有相同的視圖),並不生成單獨的CATEXP.SQL,因而造成視圖與Export代碼不同步,較難保持彼此之間的相容,用戶就必須建立自己的 Export應用,從而避免ORA-00942的錯誤。

  相應的英文如下:

  Cause: The table or view entered does not exist, a synonym that is jnot allowed here was used, or a view was referenced where a table is required.Existing user tables and views can be listed by querying the data dictionary. Certain privileges may required to access the table. If an application returned this message, the table the application tried to access does not exist in the database, or the application does not have access to it.

  Action: Check each of the following:

  The spelling of the table or view name.

  That a view is not specified where a table is required.

  That an existing table or view name exists.

  Contact the database administrator if the table needs to be created or if user or application priviledes are required to access the table.

  Also, if attempting to access a table or view in another schema, make certain thecorrect schema is referenced and that access to the object is granted.

  ORA-01598:rollback segment "name" is not online

  Cause: The rollback segment was taken offline either manually or by SMON.

  Action: Check the status of the rollback segment in DBA_ROLLBACK_SEGS.

  ORA-1636: rollback segment "name" is already online

  Cause: A rollback segment can only be used by one instance and an instance is trying to bring a rollback segment online that is already in use.

  Action: Check that the values set in the initialization parameter file for parameters

  ROLLBACK_SEGMENTS, ROLLBACK_SEGMENT_INITIAL, and ROLLBACK_SEGMENT_COUNT are correctly set for the instance whiththe problem. Also check that the instance is using the correct initialization parameter file. Make sure you are not confused about the difference between private and public rollback segments. See the Oracle8 Server Administrator’s Guide for more information about using rollback segments in paraller mode.

  上述錯誤均為我們在使用回滾段時比較常見的問題,ORA-01598指明當前使用的回滾段的狀態為 “not online”,不能使用,將它改為“online”狀態即可使用;ORA-01636指明當前回滾段已經為“online”狀態,可以直接使用,不用再 集合它。

  ORA-1636 signalled during: alter rollback segment rb00 online

  我們在做統計時還可能遇到下述問題:一個rollback segment的狀態為”Needs Recovery”的現象,這是由於ORACLE回退一個事物表中的沒有提交的事物時失敗所造成的。通常原因為一個datafile或者 tablespace是在offline的狀態或者一個undo的目標被破壞或者rollback segment被破壞。解決的辦法是將所有的tablespacedatafile都置為online狀態,如果不能解決則做下面的工作:

  1. initsid.ora中加入event="10015 trace name context forever lever 10";

  2. shutdown資料庫然後重啟;

  3. $ORACLE_HOME/rdbms/log下,找到startup時生成的trace file;

  4. trace檔中,找到下列資訊"error recovery tx(#,#) object #";

  5. 根據object#(sys.dba_objects表中的object_id相同)sys.dba_objects表中查出該object的名字;

  6. 將該object drop;

  7. init.ora檔中將該rollback segment放回rollback_segments參數中,刪除event;

  8. shutdown資料庫然後重啟。此時"Needs Recovery"的問題應該是完全解決了,否則就是rollback segment被破壞了。

  ORA-01688:unable to extend table name.name partition NAME by NUM in tablespace NAME

  產生原因:指定的tablespace空間已經被佔用滿,無法擴展。

  解決方法:使用“ALTER TABLESPACE ADD DATAFILE”命令增加檔系統檔和原始分區,或者增加INITIAL的大小(:alter tablespace CDRS101 default storage(next 500M pctincrease 1))應該能夠解決,否則就是有人使用你的表空間上創建了一個比較大的資料檔案導致你的表空間不夠用。

  一個報錯例子如下:

  ORA-1688: unable to extend table RMMCDR.LOCAL_CDR partition LOCAL_CDR101 by 460800 in tablespace CDRS101

  相應的英文如下:

  Cause: An extent could not be allocated for a table segment in tablespace

  Action: Use the ALTER TABLESPACE ADD DATAFILE statement to add one or more files to the specified tablespace


dbms_repair的介紹

首先是dbms_repair的限制﹕任何工具都不是萬能的﹐dbms_repair也包括其中

1)支持具有lob列﹐嵌入表和varray列的表﹐但是忽略行之外的列(out of line columns).

2)skip_corrupt_blocks和rebuild_freelists過程支持cluster,但check_object過程不支持cluster.

3)不支持索相結構表和lob索相。

4)dump_oraphan_keys過程不能用于位圖索相或基于函數的索相。

5)dump_oraphan_keys過程最多處理3950個字節長的鍵。

dbms_repair的過程名稱

check_object:檢測和報告表中或索相中的損壞

fix_corrupt_blocks:將數據塊(以前被check_object過程標記出來)標記成軟錯誤。

dump_oraphan_keys:報告指出損壞數據塊中的行的索相項(在一孤立鍵表中)

rebuild_freelists:重建對像的空間列表。
segment_fix_status:當段空間管理是auto時﹐提供確定位圖項的損壞狀態的能力。
skip_corrupt_blocks:當使用它時﹐就在掃描和索引其間﹐忽略被標記成損壞的數據塊。當不使用它時﹐當遇到被損壞的數據塊就報ora-1578錯。
admin_tables:提供用于修復的鍵表的管理函數。
當考慮到用dbms_repair定位數據壞塊時﹐建議使用如下步驟。
1) 檢測和報告損壞。
2) 評估使用dbms_repair的損益
3)使對像可用
4)修復損壞并重建丟失的數據。
具體的操作﹐轉載自http://blog.itpub.net/post/468/9121作者: yangtingkun

Oracle提供了DBMS_REPAIR包用來發現、標識並修改資料檔案中的壞塊。

任何工具都不是萬能的,使用這個包的同時會帶來資料丟失、表和索引返回資料不一致,完整性約束破壞等其他問題。因此當出現錯誤時,應當首先從物理備份或邏輯備份恢復,使用dbms_repair只是在沒有備份的情況下使用的一種手段,這種方式一般都會造成資料的丟失。

dbms_repair包的工作原理比較簡單,是將檢查到的壞塊標注出來,使隨後的dml操作跳過該塊,同時,dbms_repair包還提供了用於保存索引中包含的標注為壞塊中的鍵值,以及修復freelistsegment bitmap的過程。

有一點需要注意,dbms_repair包沒有進行授權,只有sys用戶可以執行。

下面通過一個例子來簡要介紹一下dbms_repair包的使用。

一、構造測試環境

首先建立一個測試用表空間,由於需要用UtralEdit打開資料檔案修改部分內容來類比錯誤,因此資料檔案要建的小一些。

SQL> CREATE TABLESPACE TEST DATAFILE 'E:ORACLEORADATATESTTEST.DBF' SIZE 1M
  2  EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT MANUAL;

表空間已創建。

SQL> CREATE TABLE TEST (ID NUMBER, NAME VARCHAR2(30)) TABLESPACE TEST;

表已創建。

SQL> INSERT INTO TEST SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS;

已創建6232行。

SQL> COMMIT;

提交完成。

SQL> CREATE INDEX IND_TEST_ID ON TEST (ID);

索引已創建。

SQL> CREATE INDEX IND_TEST_NAME ON TEST (NAME);

索引已創建。

為了確保oracle已經把剛才插入的資料寫到資料檔案中,現在重起資料庫。

SQL> CONN /@TEST AS SYSDBA
已連接。
SQL> SHUTDOWN
資料庫已經關閉。
已經卸載資料庫。
ORACLE 常式已經關閉。
SQL> STARTUP
ORACLE 常式已經啟動。

Total System Global Area   89201304 bytes
Fixed Size                   453272 bytes
Variable Size              62914560 bytes
Database Buffers           25165824 bytes
Redo Buffers                 667648 bytes
資料庫裝載完畢。
資料庫已經打開。

 

二、類比錯誤的產生

UtralEdit打開資料檔案,只要修改了資料檔案中任意的一個位置,都會造成資料檔案錯誤。但我們測試需要將錯誤發生位置定位在TEST表中。

SQL> CONN YANGTK/YANGTK@TEST
已連接。

SQL> SELECT SUBSTR(ROWID, 10, 6), ID, NAME FROM TEST WHERE ID = 123;

SUBSTR(ROWID         ID NAME
------------ ---------- ------------------------------
AAAAAG              123 ALL_REPCONFLICT

如何在資料檔案中找到TEST表的資料呢?可以通過ROWID來定位的記錄在資料檔案中的位置。任意選擇一條記錄(如上面ID = 123),取得它的ROWID,我們知道,ROWID1015位元表示這條記錄所在的BLOCK是資料檔案的第幾個BLOCK

A表示0B1G表示6。這說明這條記錄在資料檔案的第六個block中。

SQL> SHOW PARAMETER DB_BLOCK_SIZE

NAME                                 TYPE        VALUE
------------------------------------ ----------- ---------------
db_block_size                        integer     16384

BLOCK的大小是16k

SQL> SELECT TO_CHAR(6*16384, 'XXXXXX') FROM DUAL;

TO_CHAR
-------
  18000

SQL> SELECT TO_CHAR(7*16384, 'XXXXXX') FROM DUAL;

TO_CHAR
-------
  1C000 

UtralEdit打開資料檔案,將檔定位18000h處(以二進位方式打開,如果沒有用二進位打開,可以使用CTRL+H快捷鍵切換)。根據上面的計算,可以得出,我們要找到記錄在18000h1C000h之間。

Number類型123在資料庫存放方式為03C2021803表示佔有三位,C2表示最高位是百位,02表示最高位上是118表示低位上是23

具體的數值可以通過下面的查詢得到:

SQL> SELECT DUMP(123) FROM DUAL;

DUMP(123)
---------------------
Typ=2 Len=3: 194,2,24

SQL> SELECT TO_CHAR(194, 'XX'), TO_CHAR(2, 'XX'), TO_CHAR(24, 'XX') FROM DUAL;

TO_ TO_ TO_
--- --- ---
 C2   2  18

關於具體的NUMBER類型在資料庫中是如何存儲的,有興趣的可以參閱另一篇文章。

下面使用UtralEdit的搜索功能,查找到03C20218,將其修改為03C20216,並保存。

上面是通過oracleROWID在檔中定位,這相對來說要複雜一些。下面可以使用UtralEdit的功能達到相同的目的。

根據上面的查詢可以得到,ID = 123時,NAME的值是ALL_REPCONFLICT

下面用UtralEdit打開檔,使用CTRL+H方式切換到文本格式,直接查找ALL_REPCONFLICT字串。找到後,CTRL+H切換回二進位格式。向前跳過一個長度位元組(本例中為0F),就可以看到123的值03C20218,進行修改後,保存並退出。

SQL> SELECT * FROM TEST WHERE ID = 123;

        ID NAME
---------- ------------------------------
       123 ALL_REPCONFLICT

這時候查詢仍然可以得到正確結果,因為oracle使用了db_cache中的結果。為了讓oracle“到修改,必須重起資料庫。

SQL> CONN /@TEST AS SYSDBA
已連接。
SQL> SHUTDOWN
資料庫已經關閉。
已經卸載資料庫。
ORACLE 常式已經關閉。
SQL> STARTUP
ORACLE 常式已經啟動。

Total System Global Area   89201304 bytes
Fixed Size                   453272 bytes
Variable Size              62914560 bytes
Database Buffers           25165824 bytes
Redo Buffers                 667648 bytes
資料庫裝載完畢。
資料庫已經打開。
SQL> CONN YANGTK/YANGTK@TEST
已連接。

SQL> SELECT * FROM TEST WHERE ID = 123;
SELECT * FROM TEST WHERE ID = 123
              *
ERROR 位於第 1 :
ORA-01578: ORACLE 資料塊損壞(文件號7,塊號6
ORA-01110: 資料檔案 7: 'E:ORACLEORADATATESTTEST.DBF'

已經類比成功了壞塊,開始進入正題部分,使用DBMS_REPAIR表來處理壞塊。

 

三、使用DBMS_REPAIR包處理壞塊。

1.建立REPAIR_TABLEORPHAN_KEY_TABLE

SQL> BEGIN
  2  DBMS_REPAIR.ADMIN_TABLES (
  3  TABLE_NAME => 'REPAIR_TABLE',
  4  TABLE_TYPE => dbms_repair.repair_table,
  5  ACTION => dbms_repair.create_action,
  6  TABLESPACE => 'YANGTK');
  7  END;
  8  /

PL/SQL 過程已成功完成。

SQL> BEGIN
  2  DBMS_REPAIR.ADMIN_TABLES (
  3  TABLE_NAME => 'ORPHAN_KEY_TABLE',
  4  TABLE_TYPE => dbms_repair.orphan_table,
  5  ACTION => dbms_repair.create_action,
  6  TABLESPACE => 'YANGTK');
  7  END;
  8  /

PL/SQL 過程已成功完成。

REPAIR_TABLE用來記錄錯誤檢查結果,ORPHAN_KEY_TABLE用來記錄表壞塊中記錄在索引中對應鍵值。

這兩個表的刪除可以通過下列存儲過程完成

BEGIN
DBMS_REPAIR.ADMIN_TABLES (
TABLE_NAME => 'REPAIR_TABLE',
TABLE_TYPE => dbms_repair.repair_table,
ACTION => dbms_repair.drop_action);
END;
/

BEGIN
DBMS_REPAIR.ADMIN_TABLES (
TABLE_NAME => 'ORPHAN_KEY_TABLE',
TABLE_TYPE => dbms_repair.orphan_table,
ACTION => dbms_repair.drop_action);
END;
/

2.使用CHECK_OBJECT過程檢測壞塊。

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  2  num_corrupt INT;
  3  BEGIN
  4  num_corrupt := 0;
  5  DBMS_REPAIR.CHECK_OBJECT (
  6  SCHEMA_NAME => 'YANGTK',
  7  OBJECT_NAME => 'TEST',
  8  REPAIR_TABLE_NAME => 'REPAIR_TABLE',
  9  CORRUPT_COUNT => num_corrupt);
 10  DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt));
 11  END;
 12  /
number corrupt: 1

PL/SQL 過程已成功完成。

SQL> SELECT OBJECT_NAME, BLOCK_ID, CORRUPT_TYPE, MARKED_CORRUPT,
  2  CORRUPT_DESCRIPTION, REPAIR_DESCRIPTION
  3  FROM REPAIR_TABLE;

OBJECT_NAM   BLOCK_ID CORRUPT_TYPE MARKED_COR CORRUPT_DE REPAIR_DESCRIPTION
---------- ---------- ------------ ---------- ---------- ----------------------
TEST                6         6148 TRUE                  mark block software corrupt

這裏和oracle 文檔上面有點出入,根據oracle文檔上面介紹MARKED_CORRUPT列的值是FALSE,只有執行了FIX_CORRUPT_BLOCKS過程 才會使MARKED_CORRUPT列的值變為TRUE。懷疑oracleCHECK的同時,自動進行FIX_CORRUPT_BLOCKS的操作。

SQL> DECLARE
  2  num_fix INT;
  3  BEGIN
  4  num_fix := 0;
  5  DBMS_REPAIR.FIX_CORRUPT_BLOCKS (
  6  SCHEMA_NAME => 'YANGTK',
  7  OBJECT_NAME=> 'TEST',
  8  OBJECT_TYPE => dbms_repair.table_object,
  9  REPAIR_TABLE_NAME => 'REPAIR_TABLE',
 10  FIX_COUNT=> num_fix);
 11  DBMS_OUTPUT.PUT_LINE('num fix: ' || TO_CHAR(num_fix));
 12  END;
 13  /
num fix: 0

PL/SQL 過程已成功完成。

果然,執行FIX_CORRUPT_BLOCKS過程發現FIX0個壞塊,這一步操作可以省略不用執行。

3.使用DUMP_ORPHAN_KEYS過程來保存壞塊中的索引鍵值。

這時還存在著一個潛在的問題。表出現了壞塊,但是索引沒有損壞,通過表掃描回出現錯誤,但是通過索引掃描,仍然可以返回結果,這會造成資料的不一致性。

SQL> SELECT * FROM YANGTK.TEST WHERE ID = 123;
SELECT * FROM YANGTK.TEST WHERE ID = 123
                     *
ERROR 位於第 1 :
ORA-01578: ORACLE 資料塊損壞(文件號7,塊號6
ORA-01110: 資料檔案 7: 'E:ORACLEORADATATESTTEST.DBF'


SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

        ID
----------
       123

通過使用DUMP_ORPHAN_KEYS過程來保存壞塊中的索引鍵值,這樣當執行完SKIP_CORRUPT_BLOCKS操作後,就可以重新建立索引了。

SQL> DECLARE
  2  num_orphans INT;
  3  BEGIN
  4  num_orphans := 0;
  5  DBMS_REPAIR.DUMP_ORPHAN_KEYS (
  6  SCHEMA_NAME => 'YANGTK',
  7  OBJECT_NAME => 'IND_TEST_ID',
  8  OBJECT_TYPE => dbms_repair.index_object,
  9  REPAIR_TABLE_NAME => 'REPAIR_TABLE',
 10  ORPHAN_TABLE_NAME=> 'ORPHAN_KEY_TABLE',
 11  KEY_COUNT => num_orphans);
 12  DBMS_OUTPUT.PUT_LINE('orphan key count: ' || TO_CHAR(num_orphans));
 13  END;
 14  /
orphan key count: 549

PL/SQL 過程已成功完成。

SQL> DECLARE
  2  num_orphans INT;
  3  BEGIN
  4  num_orphans := 0;
  5  DBMS_REPAIR.DUMP_ORPHAN_KEYS (
  6  SCHEMA_NAME => 'YANGTK',
  7  OBJECT_NAME => 'IND_TEST_NAME',
  8  OBJECT_TYPE => dbms_repair.index_object,
  9  REPAIR_TABLE_NAME => 'REPAIR_TABLE',
 10  ORPHAN_TABLE_NAME=> 'ORPHAN_KEY_TABLE',
 11  KEY_COUNT => num_orphans);
 12  DBMS_OUTPUT.PUT_LINE('orphan key count: ' || TO_CHAR(num_orphans));
 13  END;
 14  /
orphan key count: 549

PL/SQL 過程已成功完成。

注意對每個索引都要執行DUMP_ORPHAN_KEYS過程。

4.使用REBUILD_FREELISTS過程來修改FREELISTS

如果壞塊發生在FREELIST列表中的中部,則FREELIST列表後面的塊都無法訪問,在這個例子中,由於是人為產生的錯誤,清楚錯誤的位置不在FREELIST中,因此可以跳過此步驟,一般情況下,無法定位壞塊位置,則需要執行改過程。

SQL> BEGIN
  2  DBMS_REPAIR.REBUILD_FREELISTS (
  3  SCHEMA_NAME => 'YANGTK',
  4  OBJECT_NAME => 'TEST',
  5  OBJECT_TYPE => dbms_repair.table_object);
  6  END;
  7  /

PL/SQL 過程已成功完成。

5.執行SKIP_CORRUPT_BLOCKS過程,是後續DML操作跳過壞塊

SQL> BEGIN
  2  DBMS_REPAIR.SKIP_CORRUPT_BLOCKS (
  3  SCHEMA_NAME => 'YANGTK',
  4  OBJECT_NAME => 'TEST',
  5  OBJECT_TYPE => dbms_repair.table_object,
  6  FLAGS => dbms_repair.skip_flag);
  7  END;
  8  /

PL/SQL 過程已成功完成。

SQL> SELECT OWNER, TABLE_NAME, SKIP_CORRUPT FROM DBA_TABLES
  2  WHERE OWNER = 'YANGTK';

OWNER                        TABLE_NAME                   SKIP_COR
---------------------------- ---------------------------- --------
YANGTK                       TEST                         ENABLED
YANGTK                       TEST1                        DISABLED
YANGTK                       TEST_AAA                     DISABLED
YANGTK                       TEST_PART                    DISABLED

已選擇4行。

6.重建索引

由於資料和索引仍然存在不一致的問題,因此必須重建索引。

SQL> SELECT * FROM YANGTK.TEST WHERE ID = 123;

未選定行

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

        ID
----------
       123

SQL> ALTER INDEX YANGTK.IND_TEST_ID REBUILD;

索引已更改。

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

        ID
----------
       123

注意一點,重建索引一點要先DROP,然後再CREATE,使用REBUILD的方式,重建的資料源來自索引,仍然會導致問題的產生。

SQL> DROP INDEX YANGTK.IND_TEST_ID;

索引已丟棄。

SQL> DROP INDEX YANGTK.IND_TEST_NAME;

索引已丟棄。

SQL> CREATE INDEX YANGTK.IND_TEST_ID ON YANGTK.TEST(ID);

索引已創建。

SQL> CREATE INDEX YANGTK.IND_TEST_NAME ON YANGTK.TEST(NAME);

索引已創建。

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

未選定行

SQL> SELECT MIN(ID) FROM YANGTK.TEST;

 

   MIN(ID)

----------

550