« 実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その1 | トップページ | 実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その3 »

2024年7月23日 (火) / Author : Hiroshi Sekiguchi.

実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その2

Previously on Mac De Oracle
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その1では、参照整合性制約を利用した Join Elimination の挙動を確認しました。

PostgreSQL、意外にも(知ってたくせに〜w)行われませんでしたね MySQLは事前の想定通りでしたが:)

では、次の Join Elimination のテストケースを確認してみましょう。

シンプルな例で試しています。Oracle Database / PostgreSQL / MySQL それぞれに以下の2表を作成しておきます。
どちらの表も id 列が主キーですが、前回のケースのような参照整合性制約はありません。

Oracle Database同様の表をMySQL/PostgreSQLにも作成して検証。(データはあってもなくても結合の除外には影響しないためデータは登録していません)
(なおデータ型は、MySQL/PostgreSQLに合わせて変更しています。e.g. NUMBER->INTEGER, VARCHAR2 -> VARCHAR。 また、MySQL/PostgreSQLそれぞれで統計情報も取得しておきます)

SCOTT@orclpdb1> CREATE TABLE foo (id NUMBER PRIMARY KEY, note VARCHAR2(100));

表が作成されました。

SCOTT@orclpdb1> CREATE TABLE bar (id NUMBER PRIMARY KEY, memo VARCHAR2(100));

表が作成されました。

SCOTT@orclpdb1> !cat gather_tab_stats.sql
set verify on
exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>upper('&1'),cascade=>true,no_invalidate=>false);
set verify off
undefine 1

SCOTT@orclpdb1> @gather_tab_stats foo

PL/SQLプロシージャが正常に完了しました。

SCOTT@orclpdb1> @gather_tab_stats bar

PL/SQLプロシージャが正常に完了しました。

前述の表を使い、以下のSQL文を実行します!
このSQL文では、bar表を外部結合していますが、SELECTリストでは bar表 を参照していません。
また、foo.id = bar.id は 1 : 0..1 であるため、bar表の対象行の結合されるかどうかは問合せ結果に影響しないようにしてあります。つまり、bar表は結合しなくてもよい問合せにしてあります。。。
(さあ、どうなるでしょうね。楽しくなってきました)

SELECT
foo.id
, foo.note
FROM
foo
LEFT OUTER JOIN bar
ON
foo.id = bar.id;


Oracle Database (21c)
すばらしい。無駄な結合を見つけ、Join Elimination していることを確認できます。(分かってましたけどw)

SCOTT@orclpdb1> l
1 EXPLAIN PLAN FOR
2 SELECT
3 foo.id
4 , foo.note
5 FROM
6 foo
7 LEFT OUTER JOIN bar
8 ON
9* foo.id = bar.id
SCOTT@orclpdb1> /

解析されました。

経過: 00:00:00.01
SCOTT@orclpdb1> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
Plan hash value: 1245013993

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 65 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| FOO | 1 | 65 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------

8行が選択されました。


PostgreSQL (16.3)
おおおおおおおーーーーーーーっ。このケースでは、PostgreSQLも Join Elimination しています!!!!!
bar表が結合されていません! これまた新しい気づき。メモメモw

PostgreSQLのプランナー。 Join Elimination を全く実装していないのかと思いましたが、限定的なようですが、 Join Elimination が実装されているように見えますよね。
興味深い。発展途上というところか。。(次回のPostgreSQL アンカンファレンスで聞いてみようかな)

perftestdb=> EXPLAIN verbose
perftestdb-> SELECT
perftestdb-> foo.id
perftestdb-> , foo.note
perftestdb-> FROM
perftestdb-> foo
perftestdb-> LEFT OUTER JOIN bar
perftestdb-> ON
perftestdb-> foo.id = bar.id;

QUERY PLAN
------------------------------------------------------------
Seq Scan on public.foo (cost=0.00..0.00 rows=1 width=222)
Output: foo.id, foo.note
(2 行)

MySQL (8.0.36)
んーーーーっ。MySQLのオプティマイザーは、Join Elimination は考慮していないように見えますよ。軽量なオプティマイザーが売りだからだろうか。。

mysql> EXPLAIN format=tree
-> SELECT
-> foo.id
-> , foo.note
-> FROM
-> foo
-> LEFT OUTER JOIN bar
-> ON
-> foo.id = bar.id;
+-----------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------+
| -> Nested loop left join (cost=0.7 rows=1)
-> Table scan on foo (cost=0.35 rows=1)
-> Single-row covering index lookup on bar using PRIMARY (id=foo.id) (cost=0.35 rows=1)
|
+-----------------------------------------------------------------------------------------------+
1 row in set (0.03 sec)


海外のブログでは、実装されてない! と言い切られているのもありましたが、PostgreSQL 16 では限定的ですが行われるようですね。(PostgreSQL 16より前のリリースってどうなんだろう。。13のままにしてたほうがおもしろかったかな。。。むむむ


ということで、次回へつづく。




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ヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 24 / No.59 / SQL MACRO (19.7〜)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 25 / No.60 / ANSI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.60 / ANSI JOINのおまけ
実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.61 / ANSI JOINのおまけのおまけ
実行計画は, SQL文のレントゲン写真だ! No.62 / ORDBMS機能であるコレクション型の列をアクセスする実行計画ってどうなるの?
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その1

| |

コメント

コメントを書く