実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL Tweet
さあ, 今年もやってきましたよ. 12月の風物詩ITアドベントカレンダーの季節が loL. 今年は久々に, 復活
実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺
最後まで体力とネタが持つでしょうかww (いや, なんとしてもネタを持たせないと
帰ってきた! 実行計画は、SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022
Day 1の窓は, 他のデータベースでも話題になっている標準SQLへの対応ネタから.
Oracle 19cまでは未対応だった, いくつかの集合演算子が, 20c以降でサポートされるようになりました.
簡単なとこからですよー!(最初から飛ばしすぎると後半息切れするのでw)
前述の集合演算子の拡張で特徴的だなと感じたのは, 今までALLがサポートされていなかった演算子でALLが使えるようになった事ですよね!
今回は, ALLがサポートされたINTERSECTの実行計画を見て見ましょう.
INTERSETのレントゲンは以前も紹介していました(Oracle 19c以前の実行計画)
https://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2019/12/post-9e4acc.html
今回のアドベントカレンダーでは, Oracle Database 21c Enterprise Edition を使います. (比較の為に, 旧リリースを使う場合もあります)
SCOTT@orclpdb1> select banner from v$version;
BANNER
------------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
groupa表と, groupbh表を用意しました. num列だけの単純な表です(なお, 索引は作っていません. 理由は単純な集合演算を行いたかったから:)
SCOTT@orclpdb1> @day1
1 SELECT
2 num
3 FROM
4* groupa
NUM
----------
1
2
2
3
4
4
5
7行が選択されました.
1 SELECT
2 num
3 FROM
4* groupb
NUM
----------
0
2
3
3
4
4
4
7
8行が選択されました.
上記のようなデータがあったとして, INTERSECT ALLするとどうなるか.
1 SELECT
2 num
3 FROM
4 groupa
5 INTERSECT ALL
6 SELECT
7 num
8 FROM
9* groupb
NUM
----------
2
3
4
4
INTERSECTION ALL HASH と出てますね. 21cではこれを手がかりに, INTERSECT ALL行われていると判断できますね.
INTERSECTION ALL, このケースだとHASH操作を組み合わせてる. ふむむむ 21cだからですかね. 以前まではなかったはずなので, 後半で19cを利用して試してみましょう.
実行計画
----------------------------------------------------------
Plan hash value: 2581184127
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | INTERSECTION ALL HASH| | | | | |
| 2 | TABLE ACCESS FULL | GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------
では, 以前のリリースからあったALL無しだとどうなるか. HASH操作も出てますね. 興味深い. 大量データを扱う場合は有利でしょうね.
1 SELECT
2 num
3 FROM
4 groupa
5 IINTERSECT
6 SELECT
7 num
8 FROM
9* groupb
NUM
----------
2
3
4
実行計画
----------------------------------------------------------
Plan hash value: 3344747026
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | INTERSECTION HASH | | | | | |
| 2 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------
では, HASHが選ばれない場合の簡単な例を.
表定義はこんな感じ. (削除フラグ!!!があるけど気にしないでね. 他のネタでも使いたいのでw)
名前 NULL? 型
----------------------------------------- -------- ----------------------------
UNIQUE_ID NOT NULL NUMBER(10)
SUB_ITEM_CODE NOT NULL CHAR(10)
FOO NOT NULL VARCHAR2(500)
IS_DELETE NOT NULL NUMBER(1)
名前 NULL? 型
----------------------------------------- -------- ----------------------------
UNIQUE_ID NOT NULL NUMBER(10)
SUB_ITEM_CODE NOT NULL CHAR(10)
FOO NOT NULL VARCHAR2(500)
IS_DELETE NOT NULL NUMBER(1)
索引関連はこんな感じ(索引スキャンしてもらうことを狙っています)
TABLE_NAME INDEX_NAME INDEX_TYPE UNIQUENESS
------------------------------ ------------------------------ ------------------------------ ---------------------------
TAB311 TAB311_PK NORMAL UNIQUE
TAB311 TAB311_IX_SUB_ITEM_CODE NORMAL NONUNIQUE
TAB312 IX01_TAB312 NORMAL NONUNIQUE
TAB312 IX02_TAB312 NORMAL NONUNIQUE
TABLE_NAME INDEX_NAME COLUMN_NAME
------------------------------ ------------------------------ ------------------------------
TAB311 TAB311_IX_SUB_ITEM_CODE SUB_ITEM_CODE
TAB311 TAB311_PK UNIQUE_ID
TAB311 TAB311_PK SUB_ITEM_CODE
TAB312 IX01_TAB312 UNIQUE_ID
TAB312 IX02_TAB312 SUB_ITEM_CODE
TAB312 IX01_TAB312 SUB_ITEM_CODE
以下のようなデータを用意しました.
1 SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6* unique_id BETWEEN 1 AND 50
UNIQUE_ID
----------
1
1
1
2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
53行が選択されました.
1 SELECT
2 unique_id
3 FROM
4 tab312
5 WHERE
6* unique_id BETWEEN 25 AND 75
UNIQUE_ID
----------
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
51行が選択されました.
INTERSECにしてみました. 索引が利用できる程度の取得件数なので索引を利用したSORT UNIQNE NOSORTが実行されています.
状況によっては, このようなケースもあることを思えておきましょうね. 索引利用が妥当なのかは個別の条件に応じて判断していく必要があります.
この場合は問題はないでしょう. ポイントはIndex only scanで必要最小限の範囲をアクセスして, かつ, 索引を利用してソートを回避しているところですね.
1 SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 INTERSECT
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75
UNIQUE_ID
----------
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
26行が選択されました.
実行計画
----------------------------------------------------------
Plan hash value: 547955931
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 612 | 8 (25)| 00:00:01 |
| 1 | INTERSECTION | | | | | |
| 2 | SORT UNIQUE NOSORT| | | | | |
|* 3 | INDEX RANGE SCAN | TAB311_PK | 50 | 300 | 3 (0)| 00:00:01 |
| 4 | SORT UNIQUE NOSORT| | | | | |
|* 5 | INDEX RANGE SCAN | IX01_TAB312 | 52 | 312 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=50)
5 - access("UNIQUE_ID">=25 AND "UNIQUE_ID"<=75)
おまけ, 19cでは INTERSECT ALLはサポートされいませんが, 実行計画の違いを見ておきましょう.
SCOTT@ORCL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SCOTT@ORCL> @day1
1 SELECT
2 num
3 FROM
4* groupa
NUM
----------
1
2
2
3
4
4
5
7 rows selected.
1 SELECT
2 num
3 FROM
4* groupb
NUM
----------
0
2
3
3
4
4
4
7
19cでは当然, シンタックスエラーです.
1 SELECT
2 num
3 FROM
4 groupa
5 INTERSECT ALL
6 SELECT
7 num
8 FROM
9* groupb
INTERSECT ALL
*
ERROR at line 5:
ORA-00928: missing SELECT keyword
21cでは, HASH操作が行われてましたが, 19cでは, HASHの代わりに, SORT UNIQUEが現れていますね. 興味深い違いです. それぞれのリリースで同一統計情報で操作が変化する点は, しっかり押さえておきましょう. 今後のチューニングに役立つかもしれませんよー.
1 SELECT
2 num
3 FROM
4 groupa
5 INTERSECT
6 SELECT
7 num
8 FROM
9* groupb
NUM
----------
2
3
4
Execution Plan
----------------------------------------------------------
Plan hash value: 2012227029
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | INTERSECTION | | | | | |
| 2 | SORT UNIQUE | | 7 | 21 | 4 (25)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 4 | SORT UNIQUE | | 8 | 24 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
参考)
19c UNION [ALL], INTERSECTおよびMINUS演算子
ひとまず, Day 1の窓をあけた. 明日に続く.
最後に、今回は、ORDER BY句を付加していませんが、付けてくださいよ。ソートが必要な場合は!!!!
今回の例ではたまたま昇順に並んでいるだけですからね。
Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
| 固定リンク | 0
コメント