WHERE句にリテラルの条件を入れることでクエリをスキップ

オプティマイザはデータベース列ではない定数や変数の比較をまず実行するように、
実行計画を生成する。らしい。


たとえば、こんなSQLがあったとします。

SELECT * FROM A
WHERE ・・・
UNION ALL
SELECT * FROM A
WHERE ・・・


このSQLはこんな内容だったとします。
・最初のSELECTと後のSELECTではとってくるデータに重複がない
・場合によっては、最初のSELECTだけで欲しいデータが取れる


このような場合、最初のSELECTだけで欲しいデータが取れるのに、後のSELECTも実行して(検索結果0件)しまうのは
不効率です。


うまいことやる方法の1つとして

SELECT * FROM A
WHERE &v = 'HOGE' AND ・・・
UNION
SELECT * FROM A
WHERE &v = 'BAR' AND ・・・

のように、リテラルを条件に入れます。(『&v』はバインド変数)


バインド変数が'HOGE'の場合、

SELECT * FROM A
WHERE 'HOGE' = 'HOGE' AND ・・・
UNION
SELECT * FROM A
WHERE 'HOGE' = 'BAR' AND ・・・

のようなSQLになり、後のSELECTは検索しにいかずにスキップします。


AUTOTRACEの実行計画をみてみましょう。

実行計画
----------------------------------------------------------
Plan hash value: 1012658812
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |  1000K|  3906K|   375   (9)| 00:00:05 |
|   1 |  UNION-ALL          |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL | TBL  |  1000K|  3906K|   375   (9)| 00:00:05 |
|*  3 |   FILTER            |      |       |       |            |          |
|   4 |    TABLE ACCESS FULL| TBL  |  1000K|  3906K|   375   (9)| 00:00:05 |
----------------------------------------------------------------------------


うーみゅ、これでは後のSELECTがスキップされたのか、ようわからん。


TKPROFで実行計画をみてみましょう。

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0         35          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch    66668      2.96       3.34          0      68131          0     1000000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    66670      2.96       3.35          0      68166          0     1000000

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 5  (SYSTEM)

Rows     Row Source Operation
-------  ---------------------------------------------------
1000000  UNION-ALL  (cr=68131 pr=0 pw=0 time=18009059 us)
1000000   TABLE ACCESS FULL TBL (cr=68131 pr=0 pw=0 time=5002359 us)
      0   FILTER  (cr=0 pr=0 pw=0 time=12 us)
      0    TABLE ACCESS FULL TBL (cr=0 pr=0 pw=0 time=0 us)


Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   MODE: ALL_ROWS
1000000   UNION-ALL
1000000    TABLE ACCESS   MODE: ANALYZED (FULL) OF 'TBL' (TABLE)
      0    FILTER
      0     TABLE ACCESS   MODE: ANALYZED (FULL) OF 'TBL' (TABLE)


おお!後のSELECTがまったく処理されていないことがわかりました!