UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL
[TABLE]は、7億行を超えるOracleデータベーステーブルです。 SQLの実行を6時間実行した後、キャンセルしました。
パフォーマンスを向上させる可能性のあるSQLヒントはありますか?またはそれをスピードアップする他の解決策はありますか?
EDIT:このクエリは一度実行され、その後は二度と実行されません。
まず第一に、それは1回限りのクエリですか、それとも繰り返しクエリですか?一度だけ実行する必要がある場合は、クエリを並列モードで実行することを検討することをお勧めします。とにかくすべての行をスキャンする必要があります。ワークロードをROWID(日曜大工の並列処理)の範囲で自分で分割するか、Oracleの組み込み機能を使用することができます。
頻繁に実行し、このクエリを最適化する場合、field
列がNULLの行数は、最終的には行の総数に比べて少なくなります。その場合、インデックスは物事をスピードアップする可能性があります。 Oracleは、すべてのインデックス付き列を持つ行にNULLとしてインデックスを付けないため、field
のインデックスはクエリで使用されません(field
がNULLであるすべての行を検索するため)。
どちらか:
(FIELD, 0)
_にインデックスを作成すると、_0
_はNULL以外の疑似列として機能し、すべての行がテーブルにインデックス付けされます。_(CASE WHEN field IS NULL THEN 1 END)
_に関数ベースのインデックスを作成します。これにより、NULLである行のみにインデックスが付けられます(したがって、インデックスは非常にコンパクトになります)。その場合、クエリを書き直す必要があります。
UPDATE [TABLE] SET [FIELD]=0 WHERE (CASE WHEN field IS NULL THEN 1 END)=1
これは1回限りのシナリオであるため、PARALLEL
ヒントを使用することをお勧めします。
_SQL> EXPLAIN PLAN FOR
2 UPDATE /*+ PARALLEL(test_table 4)*/ test_table
3 SET field=0
4 WHERE field IS NULL;
Explained
SQL> select * from table( dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4026746538
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 22793 | 289K| 12 (9)| 00:00:
| 1 | UPDATE | TEST_TABLE | | | |
| 2 | PX COORDINATOR | | | | |
| 3 | PX SEND QC (RANDOM)| :TQ10000 | 22793 | 289K| 12 (9)| 00:00:
| 4 | PX BLOCK ITERATOR | | 22793 | 289K| 12 (9)| 00:00:
|* 5 | TABLE ACCESS FULL| TEST_TABLE | 22793 | 289K| 12 (9)| 00:00:
--------------------------------------------------------------------------------
_
他のユーザーがテーブルの同じ行を同時に更新していますか?
もしそうなら、あなたは(ロックを待っている)多くの並行性の問題にぶつかる可能性があり、それをより小さなトランザクションに分割する価値があるかもしれません。
DECLARE
v_cnt number := 1;
BEGIN
WHILE v_cnt > 0 LOOP
UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL AND ROWNUM < 50000;
v_cnt := SQL%ROWCOUNT;
COMMIT;
END LOOP;
END;
/
ROWNUM制限が小さいほど、発生する同時実行/ロックの問題は少なくなりますが、テーブルスキャンに費やす時間は長くなります。
ヴィンセントはすでにあなたの質問に完全に答えました、しかし私はこの行動の背後にある「なぜ」について興味があります。すべてのNULLを0に更新するのはなぜですか?
よろしく、ロブ。
いくつかの提案:
UPDATEステートメントを実行する前にFIELDを含むインデックスをすべて削除し、後で再度追加します。
これを行うために、1000行または10000行ごとにコミットするPL/SQLプロシージャを記述します。
お役に立てれば。
ALTERテーブルを使用して列の「DEFAULT」値を0に設定することにより、更新せずに同じ結果を得ることができます。