7

Oracle データベースで大量の (最大 1000000 までの) SQL ステートメントを実行する必要があります。これらのステートメントは、最後に参照整合性のある状態になる必要があり、エラーが発生した場合はすべてのステートメントをロールバックする必要があります。これらのステートメントは参照順ではありません。そのため、外部キー制約が有効になっている場合、ステートメントの 1 つが外部キー違反を引き起こす可能性がありますが、この違反は後で実行されるステートメントで修正されます。

最初に外部キーを無効にして、すべてのステートメントが実行された後に有効にしようとしました。実際に外部キー違反があったときにロールバックできると思っていました。私は間違っていましたが、Oracle のすべての DDL ステートメントはコミットで始まっていることがわかったので、この方法でステートメントをロールバックする方法はありませんでした。外部キーを無効にするスクリプトは次のとおりです。

begin 
  for i in (select constraint_name, table_name from user_constraints
            where constraint_type ='R' and status = 'ENABLED') 
    LOOP execute immediate 'alter table '||i.table_name||' disable constraint 
                           '||i.constraint_name||''; 
  end loop;
end;

いくつかの調査の結果、この場合のように自律型トランザクションで DDL ステートメントを実行することが推奨されていることがわかりました。そこで、自律型トランザクションで DDL ステートメントを実行しようとしました。これにより、次のエラーが発生しました。

ORA-00054: リソースがビジーで、NOWAIT を指定して取得しています

これは、メイン トランザクションがまだテーブルに対して DDL ロックを保持しているためだと推測しています。

ここで何か間違ったことをしていますか、またはこのシナリオを機能させる他の方法はありますか?

4

1 に答える 1

8

いくつかの潜在的なアプローチがあります。

最初に考慮すべきことは、テーブルレベルで行うことはすべて、そのテーブルを使用するすべてのセッションに適用されるということです。そのテーブルへの排他的アクセス権を持っていない場合は、制約を削除/再作成したり、制約を無効/有効にしたりしたくないでしょう。

次に考慮すべきことは、100万回の挿入/更新をロールバックする立場になりたくないということです。ロールバックが遅くなる可能性があります。

通常、一時テーブルにロードします。次に、一時テーブルから宛先テーブルへの単一のINSERTを実行します。単一のステートメントとして、Oracleは最後にすべてのチェック制約を適用します。

一時テーブルを通過できない場合(たとえば、既存のデータの更新)、開始する前に、制約を最初はすぐに延期可能にします。次に、セッション内で、

SET CONSTRAINTS emp_job_nn, emp_salary_min DEFERRED;

その後、変更を適用できます。コミットすると、制約が検証されます。

違反の原因となっている行を特定するのに役立つため、DMLエラーログについてよく理解しておく必要があります。

于 2010-03-01T05:15:15.637 に答える