所以我有一个名为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;
Run Code Online (Sandbox Code Playgroud)
当我的表最初填充时,没有问题.我的问题是,当我在表上执行插入/更新并尝试通过直接更改列或仅更新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;
Run Code Online (Sandbox Code Playgroud)
这是我的前任写的,但基本上所做的只是转动给定的数值并将其转换为间隔值.
非常感谢任何帮助或建议.
谢谢.
请尝试以下操作:
SELECT *
FROM ALL_OBJECTS
WHERE OBJECT_ID = 97523
Run Code Online (Sandbox Code Playgroud)
这将告诉您Oracle遇到问题的对象。最有可能是您怀疑的索引,但也许不是。
分享并享受。
我认为发生这种情况是因为您的触发器具有非确定性函数 - > 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)
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你 !!