数百万行のテーブルを数十万行を含むテーブルに結合するクエリがあります。スキーマ所有者「ABC」は小さいテーブルを所有し、スキーマ所有者「DEF」は大きいテーブルを所有します。どちらにも、各テーブルに対する選択、挿入、削除の権限がありますが、「DEF」にはSELECT CATALOGの役割もあります。
同じテーブルの異なるバージョンを指すシノニムはありません。
ユーザー「ABC」からEXPLAINプランを実行すると、結合メカニズムとしてNESTED LOOPが表示され、クエリが実行されます。 「DEF」ユーザー(SELECT CATALOGを使用するユーザー)からEXPLAINedしたときの同じクエリは、HASH結合を示しています。この場合、HASH結合がより効率的であるように見えますが、それは質問にはほとんど関係ありません。
私の質問は、クエリを実行しているユーザーに応じて、オプティマイザが同じクエリに対して異なる結合を選択するのはなぜですか?
一般に、2つのクエリが同一である場合、それらは同じsql_idを持ち、結果として同じ実行プランを持ちます(これは時間の経過とともに変化する可能性がありますが、どのユーザーがクエリを実行するかには依存しません)。 (** 11g以降、Oracleはバインド変数の値、ヒストグラムの存在に基づいて複数のプランを生成できるため、単純化しすぎています)。
したがって、最初に、それらが本当に同一であるかどうかを確認します。両方を実行して、v $ sql/v $ sql_areaを確認します。
もう1つはOPTIMIZER_MODEです。 FIRST_ROWS(N)に設定されている場合、オプティマイザはHASH/MERGE JOINSよりもNESTED LOOPSを優先します。 ALL_ROWSの場合、オプティマイザにはHASH JOINがより適しています。異なるユーザーが異なるオプティマイザモードを設定することはごく一般的です。FIRST_ROWSはOLTPアプリケーションに最適です。ALL_ROWSはDSSに適しています。
アウトラインが使用されているかどうかも確認できます。
Oracle 11以降を使用している場合は、v $ sqlの_IS_BIND_AWARE
_、_IS_BIND_SENSITIVE
_の値を確認してください。
最後に、常に実際の実行計画を_dbms_xplan.display_cursor
_で確認し、クエリを実行せずにEXPLAIN
の出力にあまり依存しないでください。
-クエリを実行
-v $ sqlでsql_idを検索
-チェックプランSELECT * FROM table(dbms_xplan.display_cursor('[sql_id from previous step'],null));