問題
これら 2 つの Oracle Syntax Update クエリのわずかな違いのように見えるものが、根本的に異なる実行計画を引き起こしている理由を理解しようとしています。
クエリ 1:
UPDATE sales s
SET status = 'DONE', trandate = sysdate
WHERE EXISTS (Select *
FROM tempTable tmp
WHERE s.key1 = tmp.key1
AND s.key2 = tmp.key2
AND s.key3 = tmp.key3)
クエリ 2:
UPDATE sales s
SET status = 'DONE', trandate = sysdate
WHERE EXISTS (Select rownum
FROM tempTable tmp
WHERE s.key1 = tmp.key1
AND s.key2 = tmp.key2
AND s.key3 = tmp.key3)
ご覧のとおり、2 つの唯一の違いは、クエリ 2 のサブクエリがすべての行の値ではなく、rownum を返すことです。
これら 2 つの実行計画は、これ以上の違いはありません。
Query1 - 両方のテーブルから合計結果を取得し、並べ替えとハッシュ結合を使用して結果を返します。これは、有利な 2,346 コストでうまく機能します (EXISTS 句と結合サブクエリを使用しているにもかかわらず)。
クエリ 2 - 両方のテーブル結果も取得しますが、カウントとフィルターを使用して同じタスクを実行し、驚くべき 77,789,696 コストの実行プランを返します! 彼のクエリは私にかかっているだけなので、実際にはこれが同じ結果を返すとは確信していません(そうあるべきだと思いますが)。
Exists 句についての私の理解では、これはメイン テーブルの行ごとに実行される単純なブール値チェックです。EXISTS 条件で単一の行が返されるか、100,000 行が返されるかは問題ではありません...実行されている行に対して結果が返された場合、存在チェックに合格しています。では、サブクエリの SELECT ステートメントが何を返すかが問題になるのはなぜでしょうか?
- - - - - - - - - - 編集 - - - - - - - - - - -
リクエストごとに、以下は TOAD で実行している実行プランです... 上記の例ではテーブル名を簡単に編集したことに注意してください。
また、言及する必要がありましたが、この時点では2つのテーブルのどちらにもインデックスがありません..まだtempTableに追加しておらず、フィールドとデータのみを含みインデックスを含まないsalesテーブルの安価なコピーでテストしています、制約またはセキュリティ。
みんな助けてくれてありがとう!
クエリ 1 実行計画
クエリ 2 実行計画
------------------------------------------------
質問
1) rownum の呼び出しによって実行計画が変更されたのはなぜですか?
2) 信じられないほど非効率なフィルターの原因は何ですか?
3) この変更の原因となっている Exists 句の動作方法に根本的な何かが欠けていますか?