1

この質問は、サブクエリで複数のテーブルを使用するセミ結合に関する明らかなオラクルの制限を回避する方法です。次の 2 つの UPDATE ステートメントがあります。

更新 1:

UPDATE
     (SELECT a.flag update_column
      FROM a, b
      WHERE a.id = b.id AND
            EXISTS (SELECT NULL
                    FROM c
                    WHERE c.id2 = b.id2 AND
                          c.time BETWEEN start_in AND end_in) AND
            EXISTS (SELECT NULL
                    FROM TABLE(update_in) d
                    WHERE b.time BETWEEN d.start_time AND d.end_time))
SET update_column = 'F'

実行計画は、これが 2 つの準結合を正しく実行し、更新が数秒で実行されることを示しています。は と とは異なり、 ではc.id2一意の外部キーではないため、これらは半結合である必要があります。また、配列であるため、制約はまったくありません。b.id2b.ida.idupdate_in

更新 2:

UPDATE
     (SELECT a.flag update_column
      FROM a, b
      WHERE a.id = b.id AND
            EXISTS (SELECT NULL
                    FROM c, TABLE(update_in) d
                    WHERE c.id2 = b.id2 AND
                          c.time > d.time AND
                          b.time BETWEEN d.start_time AND d.end_time))
SET update_column = 'F'

これは準結合を行いません。EXISTS サブクエリに 2 つのテーブルが含まれているため、Oracle のドキュメントに基づいていると思います。テーブルのサイズとパーティショニングのため、この更新には数時間かかります。ただし、d.time関連付けられているd.start_timeと関連付ける方法d.end_timeは、同じ行にある以外にありません。ここで配列を渡してupdate_in結合する理由は、time/start_time/end_time の組み合わせごとにこのクエリをループで実行すると、パフォーマンスが低下することが判明したためです。

セミ結合が機能しない可能性がある 2 つのテーブル以外の理由はありますか? そうでない場合、この制限を回避する方法はありますか? サブクエリに2つのテーブルを入れなくてもこれらの基準を機能させることができる、私が見逃しているいくつかの簡単な解決策はありますか?

4

1 に答える 1

0

ボブが示唆するように、update_in 配列と同じ構造を持つグローバル一時テーブル (GTT) を使用できますが、主な違いは、GTT にインデックスを作成できることです。GTT に代表的なサンプル データを入力すると、次のこともできます。テーブルの統計を収集して、SQL クエリ アナライザーが最適なクエリ プランをより適切に予測できるようにします。

とはいえ、2 つのクエリには他にもいくつかの顕著な違いがあります。

  • 最初のクエリの最初の exists 句で、テーブル参照を持たない 2 つの列 start_in と end_in を参照します。私の推測では、それらはテーブル a または b の列であるか、SQL ステートメントの現在のスコープ内の変数であると考えられます。どちらかは明らかではありません。
  • 2 番目のクエリでは列 d.time を参照しますが、最初のクエリではその列を使用しません。

2 番目のクエリを次のように更新すると、パフォーマンスが向上しますか?

UPDATE
     (SELECT a.flag update_column
      FROM a, b
      WHERE a.id = b.id AND
            EXISTS (SELECT NULL
                    FROM c, TABLE(update_in) d
                    WHERE c.id2 = b.id2 AND
                          c.time BETWEEN start_in AND end_in AND
                          c.time > d.time AND
                          b.time BETWEEN d.start_time AND d.end_time))
SET update_column = 'F'
于 2015-06-24T20:52:06.553 に答える