|
在使用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 相應的英文如下: 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 space和I/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. 把event從init.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=Y的Export工具導出表,如果表空間有可用空間,先給表做一個備 份,用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的內部錯誤,只對OSS和Oracle開發有用。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已經運行,則可能是版本錯誤。 解決方法:因為Import和Export共用的一些視圖是通過運行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被破壞。解決的辦法是將所有的tablespace和datafile都置為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 一個報錯例子如下: ORA-1688: unable to extend table RMMCDR.LOCAL_CDR
partition LOCAL_CDR101 by 相應的英文如下: 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 |
Oracle提供了DBMS_REPAIR包用來發現、標識並修改資料檔案中的壞塊。
任何工具都不是萬能的,使用這個包的同時會帶來資料丟失、表和索引返回資料不一致,完整性約束破壞等其他問題。因此當出現錯誤時,應當首先從物理備份或邏輯備份恢復,使用dbms_repair只是在沒有備份的情況下使用的一種手段,這種方式一般都會造成資料的丟失。
dbms_repair包的工作原理比較簡單,是將檢查到的壞塊標注出來,使隨後的dml操作跳過該塊,同時,dbms_repair包還提供了用於保存索引中包含的標注為壞塊中的鍵值,以及修復freelist和segment
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,我們知道,ROWID中10~15位元表示這條記錄所在的BLOCK是資料檔案的第幾個BLOCK。
A表示0,B為1,G表示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快捷鍵切換)。根據上面的計算,可以得出,我們要找到記錄在18000h和1C000h之間。
Number類型123在資料庫存放方式為03C20218,03表示佔有三位,C2表示最高位是百位,02表示最高位上是1,18表示低位上是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,並保存。
上面是通過oracle的ROWID在檔中定位,這相對來說要複雜一些。下面可以使用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_TABLE和ORPHAN_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。懷疑oracle在CHECK的同時,自動進行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過程發現FIX了0個壞塊,這一步操作可以省略不用執行。
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