1.故障緣由sql
前段時間在幾個醫院發生幾回"ora-8103 對象不存在"的錯誤,出現這種錯誤,不少狀況都是bug,但也可能出如今如下幾種狀況:
-- 執行某個sql語句時
-- 錯誤出如今alertsid.LOG日誌中,通常伴隨IO錯誤.
-- dbv工具檢查發現.
錯誤的本質緣由包括:
--對象在當前操做開始後,被其餘用戶刪除.
--數據塊頭記錄的塊類型不正確.好比 數據塊的類型爲6(Type=6),但塊不是數據塊。這種狀況通常發生忽然斷電,存儲故障等狀況下。也是咱們目前遇到的最多的狀況。也就是說ora-8103,本質上多是一個塊損壞,而不是整個段都出現問題,最容易發生在操做系統或硬件故障的狀況下,特別容易發生在擴展 extent、或者是格式化新塊的時候。
--存儲數據字典中的data_object_id與塊中存儲的data_object_id不一致。一些操做可能改變對象的data_object_id,好比刪除表、trace table、重建索引,move表等。
--由於一些緣由,可能引起一個extent被兩個段使用的狀況,能夠使用以下腳本進行檢查:
本地管理表空間:
oradebug setmypid
execute dbms_space_admin.tablespace_verify('&tablespace_name')
oradebug tracefile_name
assm表空間檢查腳本:
oradebug setmypid
execute dbms_space_admin.assm_tablespace_verify ('&tablespace_name',dbms_space_admin.TS_VERIFY_BITMAPS)
oradebug tracefile_name數據庫
若是存在不一致,dbms_space_admin將會生成一個trace文件。
因爲字典管理表空間(DMT)基本不使用了,在此不作介紹。能夠參考Metalink文檔:Note 136697.1。
2.找到錯誤的對象
如何找到錯誤的對象呢?若是是SQL語句引起的錯誤,錯誤的對象要麼是表,要麼是索引。對於表,咱們能夠運行analyze來驗證:緩存
analyze table <table_name> validate structure;session
固然也能夠使用一個全表掃描的操做,能夠使用"FULL"提示字來強制查詢語句走全表掃描。對索引也一樣能夠使用analyze命令:
analyze index <index_name> validate structure;
若是是由於對象類型錯誤引起的8103錯誤,能夠使用event來跟蹤這個錯誤:
alter session set events '8103 trace name errorstack level 1';
若是是經過dbv工具進行檢測到的錯誤,dbv工具會直接報告錯誤的block id,經過block_id可查詢到具體的對象。oracle
3. 解決錯誤
若是是數據塊錯誤,能夠嘗試下列的步驟:
a. 清空數據庫高速緩存,看看這個錯誤是不是因爲內存問題引發的。10g能夠使用下列語法:ide
alter system flush buffer_cache;工具
9i及之前的版本,須要使用event:oop
alter session set events 'immediate trace name flush_cache level 1';
在RAC系統中,須要在RAC中的每一個節點都進行清空高速緩存的操做。清空高速緩存,會嚴重影響系統性能,由於全部的數據塊須要從新載入到內存中,這個操做是很是昂貴的。通常建議錯開高峯執行。性能
b.若是損壞的對象是索引,就比較好辦了,直接刪除重建這個索引便可。
c.若是損壞泊是表,就比較麻煩了。若是數據是一些沒有變化的字典表(好比,部門表、人員表這些),能夠先truncate表,再使用imp工具從備份中導入。或者使用物理備份作介質恢復。RMAN的塊恢復功能也可用於修復部分8103錯誤。
若是從備份恢復不是可行的(沒有備份,或是恢復代價太大),能夠"跳過"引起8103錯誤的的數據塊,oracle提供了一個參考的腳本:
--建立一個用來保存錯誤rowid的表
create table bad_rows (row_id rowid);
set serveroutput on
declare
nrows number;
badrows number;
begin
badrows:=0;
nrows:=0;
--使用索引構建一個循環,由於索引保存了表中全部行的rowid,注意這裏使用了index提示字來強制索引
for i in (select /*+ index (tab1) */ rowid, <indexed column name> from <original table name> tab1) loop
begin
--將"好的"數據,insert into到新表中,經過rowid讀取每一行
insert into <new table name> select
<list of columns from table (ie col1, col2,..)>
from <orig table name> where rowid=i.rowid;
if (mod(nrows,10000)=0) then commit; end if;
--若是發生錯誤,則insert錯誤的rowid到臨時表中
exception when others then
badrows:=badrows+1;
insert into bad_rows values (i.rowid);
commit;
end;
nrows:=nrows+1;
end loop;
dbms_output.put_line('Total rows: '||to_char(nrows)||' Bad rows: '||to_char(badrows));
end;
/
腳本中的關鍵是使用索引來獲取行中每一行的rowid,經過索引中保存的rowid,來取得完整的行。
還有一個方法就是使用dbms_repair表來跳過損壞的數據塊,方法與ORA-01578,的處理方法相同。spa