Oracle ORA-06512&ORA-08103對象已不存在之查詢期間表上索引被刪除

    最近,遇到一個很奇怪的問題。一Oracle數據庫的兩個存儲過程,單獨跑不會有問題,但是同時跑其中一個存儲過程

就會遇到ORA08103報錯。

    一、問題報錯信息如下:

報錯ORA-08103: 對象不再存在,ORA-06512: 在 "REPD.ETL_PPACKAGE", line 7901

--根據報錯提示,報錯涉及的SQL語句是一個Insert into ...... select

 V_SQL2:= ' INSERT INTO DATA_T (
         C1   ,
         C2  ,
        C3
          )
        SELECT
          b.T1,
          b.T2,
          b.T3,
          FROM data_b;

    二、問題分析

    1、第一印象,可能是跨用戶數據訪問,表被宿主刪掉或者報錯表上發生了truncate操作。於是,使用ddl審計監控數據

庫發生的DDL操作。

--首先sys確認觸發器相關的參數
show parameter _system_trig_enabled

--如果_system_trig_enabled參數值爲false,修改爲true
alter system set "_system_trig_enabled"=true; 

--確認觸發器相關的參數_system_trig_enabled參數值爲true
show parameter _system_trig_enabled

--SYS登陸數據庫創建審計表
-- Create table
create table AUDIT_DDL_OBJ
(
  opr_time    DATE,
  session_id  NUMBER,
  os_user     VARCHAR2(200),
  ip_address  VARCHAR2(200),
  terminal    VARCHAR2(200),
  host        VARCHAR2(200),
  user_name   VARCHAR2(30),
  ddl_type    VARCHAR2(30),
  ddl_sql     CLOB,
  object_type VARCHAR2(18),
  owner       VARCHAR2(30),
  object_name VARCHAR2(128)
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
--創建DDL審計觸發器
CREATE OR REPLACE TRIGGER DDL_Audit_Trigger
AFTER drop or alter or truncate ON DATABASE
/*
||名稱:DDL事件審計觸發器
||說明:
*/
DECLARE
   Session_Id_Var   NUMBER;          /* 會話ID */
   Os_User_Var      VARCHAR2(200);   /* 終端OS用戶 */
   IP_Address_Var   VARCHAR2(200);   /* 終端IP */
   Terminal_Var     VARCHAR2(200);   /* 終端 */
   Host_Var         VARCHAR2(200);   /* 終端主機名 */
   Cut              NUMBER;          /* SQL列表長度 */
   Sql_Text         ORA_NAME_LIST_T; /* SQL_TEXT 列表 */
   L_Trace          NUMBER;          /* 循環執行條件 */
   DDL_Sql_Var      VARCHAR2(2000);  /* DDL語句 */
   stmt     clob := NULL;
   n        NUMBER;
BEGIN
   /* 獲取操作用戶信息 */
   SELECT   SYS_CONTEXT('USERENV','SESSIONID'),
            SYS_CONTEXT('USERENV','OS_USER'),
            SYS_CONTEXT('USERENV','IP_ADDRESS'),
            SYS_CONTEXT('USERENV','TERMINAL'),
            SYS_CONTEXT('USERENV','HOST')
   INTO     Session_Id_Var,
            Os_User_Var,
            IP_Address_Var,
            Terminal_Var,
            Host_Var
   FROM     DUAL;
   /* 獲取DDL SQL語句 */
   /*BEGIN
    SELECT sql_text
      INTO DDL_Sql_Var
      FROM sys.v_$sql a, sys.v_$session b
     WHERE a.hash_value = b.sql_hash_value
       AND b.status = 'active'
       AND b.audsid = SYS_CONTEXT('userenv', 'sessionid');
   EXCEPTION
      WHEN OTHERS THEN
         NULL;
   END;*/
   n := ora_sql_txt(sql_text);
   FOR i IN 1 .. n LOOP
    stmt := stmt || sql_text(i);
   END LOOP;
   /* 記錄登陸審計信息 */
   INSERT INTO Audit_DDL_OBJ(
               Opr_Time,     /* 操作時間 */
               Session_Id,   /* 會話ID */
               OS_User,      /* 終端OS用戶 */
               IP_Address,   /* 終端IP地址 */
               Terminal,     /* 終端 */
               Host,         /* 終端主機名 */
               User_Name,    /* ORACLE 用戶名*/
               DDL_Type,     /* DDL操作類型 */
               DDL_Sql,      /* DDL語句 */
               Object_Type,  /* 操作對象類型 */
               Owner,        /* 對象擁有者 */
               Object_Name   /* 對象名稱 */
              )
       VALUES( SYSDATE,
               Session_Id_Var,
               Os_User_Var,
               IP_Address_Var,
               Terminal_Var,
               Host_Var,
               ORA_LOGIN_USER,
               ORA_SYSEVENT,
               stmt,
               ORA_DICT_OBJ_TYPE,
               ORA_DICT_OBJ_OWNER,
               ORA_DICT_OBJ_NAME);
   COMMIT;
EXCEPTION
   WHEN OTHERS THEN
      NULL;
END DDL_Audit_Trigger;
========
觸發器後期清理
drop triger DDL_Audit_Trigger;

drop table AUDIT_DDL_OBJ;

alter system set "_system_trig_enabled"=false;

    2、分析報錯的

    根據DDL審計表AUDIT_DDL_OBJ信息,沒有發現DATA_T相關的DROP、TRUNCATE操作。

    ​3、經與系統負責人溝通,採用10046跟蹤執行跑批報錯的會話

1 查詢要跟蹤的用戶會話信息
select sid,serial#,username from v$session where username='REPD';
2 開啓10046跟蹤
exec dbms_system.set_ev(sid,serial#,10046,12,'');
3 程序拋出錯誤後結束10046跟蹤
exec dbms_system.set_ev(sid,serial#,10046,0,'');
4 獲取10046跟蹤日誌文件,第1步中查詢到的sid號
 select p.tracefile from V$PROCESS p,v$session s where s.paddr=p.addr and sid=&sid;

    ​4、根據10046跟蹤文件獲取到ORA08103報錯對象的數據文件號和數據塊號

    ​5、根據10046跟蹤文件ORA08103提示的數據文件號和數據塊號,確定到insert into ..... select相關表的一個索引對象

    ​6、再次審查DDL審計觸發器,在存儲過程跑批之前,確實有該索引的drop操作

    ​7、至此ORA08103問題根源定位到

    ​導致ORA08103報錯的原因就是其中一個存儲過程在執行insert into ..... select操作過程中,另外一個存儲過程對insert 

into ... select的select部分的表上的索引執行了drop,導致select查詢異常報錯ORA08103退出。

    ​8、排查兩個同時執行報錯的存儲過程,其中一個存儲過程確實對審計表監控的索引執行了drop操作

三、問題處理

    ​經與客戶溝通後,屏蔽存儲過程中drop索引的操作,再執行存儲過程,不再有ORA08103報錯。

 

四、補充

    導致ORA08103報錯的可能原因有:

    ​1、被操作的對象確實被其他用戶刪除掉

    ​2、被操作的對象被執行了truncate操作

    ​3、系統表空間數據塊損壞導致的對象字典信息與表所在表空間數據對象信息不一致

    4、被操作對象發生了DDL例如加字段操作

    5、被操作對象上的索引被刪除,操作使用到了對象上的索引

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章