6

所以我有一个索引名为 IDX_ATS_CALC_END_TIME 的表。该列是一个时间戳值。此列还有一个触发器,当填充或更新另一列 (Interval_duration) 时会自动填充该列。

触发器如下:

TRIGGER "DATAMART"."TRG_ATS_CALC_END_TIME" 
    BEFORE INSERT OR UPDATE OF INTERVAL_DURATION ON DATAMART.AGG_TIME_SUMMARY
    FOR EACH ROW
    DECLARE
BEGIN
IF :New.INTERVAL_DURATION > 0 THEN
   :New.calc_end_time := :New.start_date_time  + pb_util.secondtointerval(:New.INTERVAL_DURATION);
ELSE
:NEW.CALC_END_TIME := :New.start_date_time;
END IF;

    EXCEPTION
    WHEN OTHERS THEN
      pb_util.logdata(1, 'TRG_ATS_CALC_END_TIME', 'Exception Thrown in interval:  ' || :New.Interval_DURATION, SQLERRM  || ' stack: ' || dbms_utility.format_error_backtrace);

END TRG_ATS_CALC_END_TIME;

最初填充我的表时,没有问题。我的问题是,当我去对表执行插入/更新并尝试通过直接更改列或仅更新 interval_duration 列来修改此列时,我抛出了这个错误:

ORA-08102: 找不到索引键,obj# 97523,文件 4,块 244 (2)

提到的索引是一个基于函数的索引。索引上使用的函数是 calc_end_time 列上的 sys_extract_utc。

我花了几天时间试图解决这个问题。我已经重建了索引,我尝试过删除并重新创建索引。这两个似乎是这个问题的常见答案,但它们对我不起作用。我使用以下方法分析了索引:

ANALYZE INDEX IDX_ATS_CALC_END_TIME VALIDATE STRUCTURE;

它回来时没有任何问题。

我唯一能够成功更新此列而不会出现此错误的方法是禁用触发器,执行更新,然后再次启用触发器。这对我来说不是一个可行的解决方案。

所以我想知道是否有人遇到过这种类型的问题,以及我可以尝试哪些其他步骤来解决这个错误。

更新: 您将在下面找到函数 pb_util.secondtointerval() 代码:

FUNCTION SecondToInterval
  (Seconds_IN NUMBER
  )
RETURN CONST.PBInterval
IS
  sec            NUMBER(20, 9);
  days           NUMBER;
  hours          NUMBER;
  minutes        NUMBER;
  seconds        NUMBER(20, 9);
  IntervalAsText NVARCHAR2(32);
  ReturnInterval INTERVAL DAY(9) TO SECOND(9);
begin
  sec     := NVL(Seconds_IN, 0);

  days    := trunc(sec/(24*60*60));
  sec     := sec - days*24*60*60;

  hours   := trunc(sec/(60*60));
  sec     := sec - hours*60*60;

  minutes := trunc(sec/60);
  sec     := sec - minutes*60;

  seconds := trunc(sec);

  sec     := sec - seconds;
  sec     := trunc(1000000000*sec);

  IntervalAsText := cast(days as nvarchar2)
    || ' ' || cast(hours as nvarchar2)
    || ':' || substr('00' || cast(minutes as nvarchar2), -2, 2)
    || ':' || substr('00' || cast(seconds as nvarchar2), -2, 2)
    || '.' || substr('000000000' || cast(sec as nvarchar2), -9, 9);

  --dbms_output.put_line(intervalastext);

  ReturnInterval := TO_DSInterval(IntervalAsText);
  --ReturnInterval := TO_DSInterval('999999999 23:59:59.999999999');
  --dbms_output.put_line(ReturnInterval);

  RETURN ReturnInterval;
EXCEPTION
    WHEN OTHERS THEN
   pb_util.logdata(1, 'PB_UTIL.SecondToInterval', 'ERROR(99A): ', intervalastext);
                dbms_output.put_line(intervalastext);
                RAISE;

end SecondToInterval;

这是我的前任写的,但基本上它所做的只是将给定的数值转换为间隔值。

非常感谢任何帮助或建议。

谢谢你。

4

2 回答 2

6

尝试以下操作:

SELECT *
  FROM ALL_OBJECTS
  WHERE OBJECT_ID = 97523

这将告诉您 Oracle 遇到问题的对象。很可能是您怀疑的索引,但也可能不是。

分享和享受。

于 2012-06-12T15:20:52.003 回答
3

我认为它正在发生,因为您的触发器具有非确定性函数-> pb_util.secondtointerval。我真的不知道这种方法的真正作用。尝试将一些静态值分配给 CALC_END_TIME 并检查您的触发器是否有效。

为了支持这一点,我在这里放置了一小段代码:

SQL> CREATE TABLE t (a INTEGER)
Table created.

SQL> CREATE OR REPLACE FUNCTION f (a INTEGER)
   RETURN INTEGER "DETERMINISTIC"
AS
   cnt   INTEGER;
BEGIN
   RETURN ROUND ("DBMS_RANDOM.VALUE (1, 100)");
END f;
Function created.

SQL> CREATE INDEX t_idx ON t (f(a)) COMPUTE STATISTICS
Index created.

SQL> INSERT INTO t
   SELECT ROWNUM
     FROM user_objects
5 rows created.

SQL> DELETE FROM t
DELETE FROM t
Error at line 28
ORA-08102: index key not found, obj# 48928, file 4, block 36 (2)

希望能帮助到你 !!

于 2012-06-12T15:13:46.287 回答