事前準備
--table作成 create table tbl1(col1 number,col2 number,col3 number); create table tbl2(col1 number,col2 number,col3 number); --インデックス作成 CREATE INDEX tbl1_idx ON tbl1(col1); CREATE INDEX tbl2_idx ON tbl2(col1); --tbl1には10件投入 begin for i in 1..10 loop insert into tbl1 values(i,i,i); commit; end loop; end; / --tbl1には1000000件投入 begin for i in 1..1000000 loop insert into tbl2 values(i,i,i); commit; end loop; end; /
確認(読み込みブロック数と実行時間)
SQL> --tbl1(件数が少ない方を駆動表にする) SQL> select /*+ USE_NL(tbl2) LEADING(tbl1) */count(1) from tbl1,tbl2 where tbl1.col2=tbl2.col2; COUNT(1) ---------- 10 経過: 00:00:00.55 実行計画 ---------------------------------------------------------- Plan hash value: 1872982815 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 26 | 7508 (1)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 26 | | | | 2 | NESTED LOOPS | | 10 | 260 | 7508 (1)| 00:00:01 | | 3 | TABLE ACCESS FULL| TBL1 | 10 | 130 | 2 (0)| 00:00:01 | |* 4 | TABLE ACCESS FULL| TBL2 | 1 | 13 | 751 (1)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter("TBL1"."COL2"="TBL2"."COL2") Note ----- - dynamic statistics used: dynamic sampling (level=2) 統計 ---------------------------------------------------------- 9 recursive calls 0 db block gets 27616 consistent gets 0 physical reads 0 redo size 573 bytes sent via SQL*Net to client 451 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk) 1 rows processed SQL> --tbl2(件数が多い方を駆動表にする) SQL> select /*+ USE_NL(tbl1) LEADING(tbl2) */count(1) from tbl1,tbl2 where tbl1.col2=tbl2.col2; COUNT(1) ---------- 10 経過: 00:00:06.35 実行計画 ---------------------------------------------------------- Plan hash value: 835256089 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 26 | 301K (1)| 00:00:12 | | 1 | SORT AGGREGATE | | 1 | 26 | | | | 2 | NESTED LOOPS | | 10 | 260 | 301K (1)| 00:00:12 | | 3 | TABLE ACCESS FULL| TBL2 | 1109K| 13M| 751 (1)| 00:00:01 | |* 4 | TABLE ACCESS FULL| TBL1 | 1 | 13 | 0 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter("TBL1"."COL2"="TBL2"."COL2") Note ----- - dynamic statistics used: dynamic sampling (level=2) 統計 ---------------------------------------------------------- 7 recursive calls 0 db block gets 3002836 consistent gets 0 physical reads 0 redo size 573 bytes sent via SQL*Net to client 451 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
まとめ
実はあまり理解できていないのですが、どちらを駆動表にしてもレコードの組み合わせの個数は同じになります。 それでもtbl1の駆動表にした方が読み込みブロック数(処理時間も)が少なくなります。
docs.oracle.com 等を確認すると駆動表をフェッチしている(最初に対象データを絞る)らしいのでその分駆動表が小さい方が速いと勝手に理解しました。