さて、これまでで、実行計画のツリーのたどり方と、ツリーの構成要素である各オペレーションで
実行されている処理の概要がわかったと思います。
しかし、これだけの情報では、実行計画と実行されたSQLのWHERE条件を対応づけて理解することは
難しいです。(できなくはありませんが、かなり推測に頼る形になります。)
SQLのWHERE条件と対応付けるためには、フィルタ述語とアクセス述語に着目する必要があります。
### Predicate Informationセクション
実行計画をDBMS_XPLAN.DISPLAY_CURSORで取得した場合、フィルタ述語とアクセス述語に関する情報は
Predicate Informationセクションに表示されます。
—————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————–
| 0 | SELECT STATEMENT | | | | 20 (100)| |
| 1 | NESTED LOOPS | | 10 | 40120 | 20 (0)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | PA | 1 | 2004 | 9 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| CH | 10 | 20080 | 11 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IDX_CHPA | 10 | | 1 (0)| 00:00:01 |
—————————————————————————————–
Predicate Information (identified by operation id): ←★
—————————————————
2 – filter(“PA”.”PID”=1)
4 – access(“CH”.”PID”=1)
Predicate Informationセクション内のフィルタ述語、アクセス述語の先頭には
オペレーション(ステップ)に対応するIdが記載されています。
### フィルタ述語の働き
フィルタ述語は、Predicate Informationではfilter(…)と記載され、
行頭の番号に対応するオペレーションの実行時に、取得したデータから
対象データを抜粋(フィルタ)する処理が実行されたことを示します。
上記の実行計画では、Id=2 TABLE ACCESS FULL において
フィルタ述語 filter(“PA”.”PID”=1) が適用されていることがわかります。
これは、表PAを全表スキャンした後に、PA表のデータのうち、pa.pid = 1という
述語(条件)にマッチする行を抜粋したことになります。
SELECT cid, cname, pa.pid, pname FROM ch, pa
WHERE ch.pid = pa.pid and pa.pid = 1
^^^^^^^^^^
今回実行したSQL(から不要なヒントを除いて整形したもの)は、上記のとおりですが、
フィルタ述語 filter(“PA”.”PID”=1) の条件は、SQLのWHERE条件に記載された
pa.pid = 1 に対応していることがわかります。
### アクセス述語の働き
アクセス述語は、Predicate Informationではaccess(…)と記載され、
行頭の番号に対応するオペレーションの実行時に、表示された述語を使用して
データにアクセスしたことを示します。
一般に、オペレーションが索引スキャン系(INDEX UNIQUE SCAN, INDEX RANGE SCAN)の場合に指定され、
索引をTraverseする(索引のroot → branch → leafとたどる)ときの索引列の検索条件に対応します。
上記の実行計画では、Id=4 INDEX RANGE SCAN において
アクセス述語 access(“CH”.”PID”=1) が適用されていることがわかります。
これは、索引IDX_CHPAの索引列CH.PIDに1という値を持つ索引エントリを探す
ことに相当します。
SELECT cid, cname, pa.pid, pname FROM ch, pa
WHERE ch.pid = pa.pid and pa.pid = 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
アクセス述語 access(“CH”.”PID”=1) は、上記SQLのWHERE条件
ch.pid = pa.pid and pa.pid = 1 を数学的/算術的に変換したものであることが
わかります。(推移律 : pa.pid=1であれば、ch.pid = pa.pidは ch.pid=1となる)
### WHERE条件とフィルタ述語、アクセス述語の対応関係
このように、フィルタ条件、アクセス条件を確認すると、
それぞれのオペレーションにおいて、SQLのWHERE条件に対応したデータの絞込みが
行われているかをはっきりと理解することができます。
効率的なSQL実行の鉄則は、初期段階においてデータをできるだけ絞り込むことですので、
万が一、データが意図したように絞り込めていない場合は実行計画を再検討することに
なります。その際に、現行の実行計画がどのオペレーションにおいて、どのWHERE条件に
対応したデータの絞込みがなされているかを理解することが重要になります。
### フィルタ述語とアクセス述語の違い
フィルタ述語とアクセス述語は、ともに述語に合致したデータのみが得られるという
点で似ていますが、処理効率の観点からは全く異なることに注意してください。
アクセス述語は一般に索引スキャン実行時に指定されますが、
アクセス述語に合致したデータにのみ選択的にアクセスします。
このため、一般にアクセスするブロック数を小さく抑えることができます。
一方、フィルタ述語は、ブロックにアクセスした後のデータを除外する際に
適用されます。アクセスした後にデータを絞り込む形になるため、
一般にアクセスするブロック数は大きくなりがちです。
したがって、どうしてもケースバイケースの側面はありますが、データの絞込みは
アクセス述語を使用する索引アクセスで行うことが一般に推奨されます。
### SQLトレースの実行計画ではフィルタ述語とアクセス述語が表示されないことに注意
理由は不明ですが、SQLトレースの実行計画にはフィルタ述語とアクセス述語が表示されません。
上記のとおり、フィルタ述語とアクセス述語は実行計画内の各オペレーションの処理内容
を理解するために非常に有効な情報です。
このため、実行計画を確認する際は、フィルタ述語とアクセス述語が出力される
DBMS_PLAN.DISPLAY_CURSOR(または類似のファンクション)を使用することを
オススメします。
[…] フィルタ述語とアクセス述語 […]