處理ora-8103錯誤

    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

相關文章
相關標籤/搜索