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 です。

この問題を解決するために数日を費やしました。インデックスを再構築しました。インデックスを削除して再作成しようとしました。これらの 2 つは、この問題に対する一般的な答えのようですが、私にはうまくいきませんでした。以下を使用してインデックスを分析しました。

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 に答える