Oracle 10gのSQL*Plusで実行計画を取得する

オブジェクトブラウザのようなソフトを使って実行計画を取得することはときどきあるけど、SQL*Plusでやったことがなかったので試してみた。次のサイトの記事を参考にした。
使っているのはOracle 10g Express Edition (XE)。

下準備が必要

以下のサイトを参考にして下準備した。
SQL*Plusで実行計画を取得する - オラクル・Oracle SQL*Plus リファレンス
以下の順序で進める。特に問題になる箇所はなかった。

  1. 「$ORACLE_HOME/sqlplus/admin/plustrce.sql」を実行して、ロール "plustrace"を作成する
  2. 通常ユーザにロール "plustrace"を付与する
  3. 「$ORACLE_HOME/admin/utlxplan.sql」を実行して、通常ユーザのスキーマでPLAN_TABLEを作成する

実行計画を取得する

こんな感じのデータがある。

SQL> select * from products;

CODE      PRICE                                                                 
---- ----------                                                                 
AA01        100                                                                 
BB01        200                                                                 
BB02        200                                                                 
DD02        300                                                                 

SQL> spool off

PRICEの値が重複していない行だけを取り出したい。
比較したい2つのSQLの実行計画を順次取得する。

spool trace.log

set lines 200
col plan_plus_exp format a200
set pages 0
set autotrace on

SELECT
A.CODE,
A.PRICE
FROM PRODUCTS A
WHERE A.PRICE IN
(
	SELECT B.PRICE
	FROM PRODUCTS B
	GROUP BY B.PRICE
	HAVING COUNT('X') = 1
)
ORDER BY 1;

SELECT MIN(code),price FROM products
GROUP BY price
HAVING COUNT(*)=1
ORDER BY 1;

spool off

得られた結果が次のようなものだった。

まずひとつめのSQLの結果。

実行計画
---------------------------------------------------------- 
Plan hash value: 3428268735                                                        
                                                                                   
-----------------------------------------------------------------------------------
| Id  | Operation              | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |          |     4 |   120 |     9  (34)| 00:00:01 |
|   1 |  SORT ORDER BY         |          |     4 |   120 |     9  (34)| 00:00:01 |
|*  2 |   HASH JOIN SEMI       |          |     4 |   120 |     8  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL   | PRODUCTS |     4 |    68 |     3   (0)| 00:00:01 |
|   4 |    VIEW                | VW_NSO_1 |     4 |    52 |     4  (25)| 00:00:01 |
|*  5 |     FILTER             |          |       |       |            |          |
|   6 |      HASH GROUP BY     |          |     4 |    52 |     4  (25)| 00:00:01 |
|   7 |       TABLE ACCESS FULL| PRODUCTS |     4 |    52 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------
                                                                                   
Predicate Information (identified by operation id):                                
---------------------------------------------------                                
                                                                                   
   2 - access("A"."PRICE"="$nso_col_1")                                            
   5 - filter(COUNT(*)=1)                                                          
                                                                                   
Note                                                                               
-----                                                                              
   - dynamic sampling used for this statement                                      


統計
----------------------------------------------------------                         
         78  recursive calls                                                       
          0  db block gets                                                         
         98  consistent gets                                                       
          0  physical reads                                                        
          0  redo size                                                             
        534  bytes sent via SQL*Net to client                                      
        384  bytes received via SQL*Net from client                                
          4  SQL*Net roundtrips to/from client                                     
          5  sorts (memory)                                                        
          0  sorts (disk)                                                          
          2  rows processed                                                        

これが2つめのSQLの結果。

実行計画
----------------------------------------------------------                         
Plan hash value: 1002956361                                                        
                                                                                   
---------------------------------------------------------------------------------  
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |  
---------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT     |          |     4 |    68 |     5  (40)| 00:00:01 |  
|   1 |  SORT ORDER BY       |          |     4 |    68 |     5  (40)| 00:00:01 |  
|*  2 |   FILTER             |          |       |       |            |          |  
|   3 |    HASH GROUP BY     |          |     4 |    68 |     5  (40)| 00:00:01 |  
|   4 |     TABLE ACCESS FULL| PRODUCTS |     4 |    68 |     3   (0)| 00:00:01 |  
---------------------------------------------------------------------------------  
                                                                                   
Predicate Information (identified by operation id):                                
---------------------------------------------------                                
                                                                                   
   2 - filter(COUNT(*)=1)                                                          
                                                                                   
Note                                                                               
-----                                                                              
   - dynamic sampling used for this statement                                      


統計
----------------------------------------------------------                         
          5  recursive calls                                                       
          0  db block gets                                                         
         15  consistent gets                                                       
          0  physical reads                                                        
          0  redo size                                                             
        539  bytes sent via SQL*Net to client                                      
        384  bytes received via SQL*Net from client                                
          4  SQL*Net roundtrips to/from client                                     
          1  sorts (memory)                                                        
          0  sorts (disk)                                                          
          2  rows processed                                                        

これを読み解くのにまた一苦労だなあ。一見すると2つめのほうがよいパフォーマンスであるようにみえる。