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がまったく処理されていないことがわかりました!