« DTM/GarageBand (N + 1 Loops ) : 8月にリリースした曲 | トップページ | 悩ませ過ぎは及ばざるがごとし (MySQL 8.0.32編) »

2023年9月 2日 (土) / Author : Hiroshi Sekiguchi.

帰ってきた! 標準はあるにはあるが癖の多いSQL #3 オプティマイザの結合順評価テーブル数上限にも癖が出る

Previously on Mac De Oracle前回の癖はw
帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出る
でした。
実は、今日の癖は、その検証時に気づいた、MySQLで結合表数が多いと、パース時間長くなってね? というか長いよね! という点。

オプティマイザは、皆さんの難しい(いや、難しい必要はないですが)SQLを無駄なく、そのSQLに見合った最短の時間で結果を返そうと努力して実行計画を立てています。これを解析フェーズとかパース時間とか、ハードパース時間とかいくつかのバリエーションで表現していたりします。
今回は、中をとってw パース時間としますね。SQL文の実行計画を立てる、オプティマイザがあれやこれや考えて実行計画を立て終えるまでの時間のことです。

先日の検証で、10表結合したのですが、MySQLでは、20秒以上要していました。実行計画でオプティマイザ考えすぎて帰ってこない。SQL文の実行ではなく実行計画を立てるところで時間がかかるケースはいくつか有名なのがありますが。
そうならないように各データベースは閾値を設けています。今回は、結合順評価テーブル数上限 ってやつです。結合する表の順序の組み合わせをどこまで検討するかということなのですが、これが、票数が増えると鰻登りに増加します。
今回のケースだと、1011表なので、10!11!ですね。2表をを繰り返し結合していてもしっかり考えてくれちゃいます。

ただ、何も考えずにオプティマイザに時間を与えていると、パース時間だけでとんでもない時間になったり、性能要件に見合わないといったケースが出てきます。なので、適当なところで手を打って、オプティマイザに考えさせ過ぎないようしています。
その閾値のデフォルト値が、MySQLとOracle/PostgreSQLとでは結構違うみたい。というところが今回の癖!

ちなみに、Oracleの例ですが、結合以外にINリストに大量にリテラルがあり、かつ考慮する必要のある索引も多いケースでは、悩ませ過ぎは及ばざるがごとし #7 - おまけなんてことも起こりますw オプティマイザを悩ませすぎると大変なので、そんな時は、SQLヒントなどを使って、オプティマイザに考えさせないという治療で回避するのが特効薬ですw

余談はこれぐらいにして、本題へ。

 

Note:
(MySQL/PostgreSQL/Oracle 23c freeそれぞれ、同一Virtualbox VMを利用して検証しているため、CPUリソース等の差異はありません)

最初は、ネタの発端になったMySQL 8.0.32から


mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.32 |
+-----------+
1 row in set (0.00 sec)

mysql> show tables;
+----------------------+
| Tables_in_perftestdb |
+----------------------+
| detail |
| master |
+----------------------+
2 rows in set (0.00 sec)

mysql> desc detail;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| subid | int | NO | PRI | NULL | |
| dummya | varchar(10) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> show indexes from detail;
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| detail | 0 | PRIMARY | 1 | id | A | 10 | NULL | NULL | | BTREE | | | YES | NULL |
| detail | 0 | PRIMARY | 2 | subid | A | 20 | NULL | NULL | | BTREE | | | YES | NULL |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.02 sec)

mysql> desc master;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| dummya | varchar(10) | YES | MUL | NULL | |
+--------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> show indexes from master;
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| master | 0 | PRIMARY | 1 | id | A | 10 | NULL | NULL | | BTREE | | | YES | NULL |
| master | 1 | ix_master | 1 | dummya | A | 10 | NULL | NULL | YES | BTREE | | | YES | NULL |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.02 sec)

mysql> analyze table master;
+-------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+-------------------+---------+----------+----------+
| perftestdb.master | analyze | status | OK |
+-------------------+---------+----------+----------+
1 row in set (0.04 sec)

mysql> analyze table detail;
+-------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+-------------------+---------+----------+----------+
| perftestdb.detail | analyze | status | OK |
+-------------------+---------+----------+----------+
1 row in set (0.02 sec)

mysql>

 

 

表定義とデータは以前のエントリーも参考に
MySQL 8.0.32 / explain analyze 実行途中でキャンセルできるみたいだけど、キャンセルしたら、Actual Plan、途中まで出るの?

 

では、

MySQL 8.0.32で、パースに時間を要するケースの再現。optimizer_search_depthパラメータはデフォルトのまま

 

MySQL : optimizer_search_depth optimizer_search_depth


mysql> show variables like 'optimizer_search_depth';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| optimizer_search_depth | 62 |
+------------------------+-------+
1 row in set (0.00 sec)

mysql> \. test1.sql
Database changed
+----------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------------------------------------------------------+
| -> Nested loop inner join (cost=7162.25 rows=10240)
-> Nested loop inner join (cost=3578.25 rows=5120)
-> Nested loop inner join (cost=1786.25 rows=2560)
-> Nested loop inner join (cost=890.25 rows=1280)
-> Nested loop inner join (cost=442.25 rows=640)
-> Nested loop inner join (cost=218.25 rows=320)
-> Nested loop inner join (cost=106.25 rows=160)
-> Nested loop inner join (cost=50.25 rows=80)
-> Nested loop inner join (cost=22.25 rows=40)
-> Nested loop inner join (cost=8.25 rows=20)
-> Index scan on master using ix_master (cost=1.25 rows=10)
-> Index lookup on detail using PRIMARY (id=`master`.id) (cost=0.52 rows=2)
-> Index lookup on t2 using PRIMARY (id=`master`.id) (cost=0.51 rows=2)
-> Index lookup on t3 using PRIMARY (id=`master`.id) (cost=0.51 rows=2)
-> Index lookup on t4 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t5 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t6 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t7 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t8 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t9 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t10 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
|
+----------------------------------------------------------------------------------------------------------------------+
1 row in set (21.37 sec)

パースに 21.37 sec 要していますね。 62!まで結合順を探査する設定ですから、このケースだと、10!まで行っているということなのでしょうね。

では、Oracleなどで設けられてる閾値と同等の 6 にせってしてみた場合のパース時間はどうでしょうね。このケースで実行計画を間違うことはない(単純なので)ですが、複雑な結合だと、実行計画をミスする率は多くなりそうですけども、Oracleとかだとその程度で使ってますし。。この程度でも良いのかもしれません。時間かかってもいいよというケースも当然あるので、非機能要件次第ではありますけどね。


mysql> set optimizer_search_depth = 6;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'optimizer_search_depth';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| optimizer_search_depth | 6 |
+------------------------+-------+
1 row in set (0.00 sec)

mysql> \. test1.sql
Database changed
+----------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------------------------------------------------------+
| -> Nested loop inner join (cost=7162.25 rows=10240)
-> Nested loop inner join (cost=3578.25 rows=5120)
-> Nested loop inner join (cost=1786.25 rows=2560)
-> Nested loop inner join (cost=890.25 rows=1280)
-> Nested loop inner join (cost=442.25 rows=640)
-> Nested loop inner join (cost=218.25 rows=320)
-> Nested loop inner join (cost=106.25 rows=160)
-> Nested loop inner join (cost=50.25 rows=80)
-> Nested loop inner join (cost=22.25 rows=40)
-> Nested loop inner join (cost=8.25 rows=20)
-> Index scan on master using ix_master (cost=1.25 rows=10)
-> Index lookup on detail using PRIMARY (id=`master`.id) (cost=0.52 rows=2)
-> Index lookup on t2 using PRIMARY (id=`master`.id) (cost=0.51 rows=2)
-> Index lookup on t3 using PRIMARY (id=`master`.id) (cost=0.51 rows=2)
-> Index lookup on t4 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t5 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t6 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t7 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t8 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t9 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
-> Index lookup on t10 using PRIMARY (id=`master`.id) (cost=0.50 rows=2)
|
+----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.27 sec)

はい! パース時間は、一気短縮され、 0.27 sec になりました。Oracleのハードパースでもこれぐらいなこんな程度だとは思います。

 

次に、PostgreSQLで確認してみましょ。 PostgreSQLの場合は、Oracleに近かったはず。表定義とデータ量は同じです。

PostgreSQLでは、結合順序評価上限は以下join_collapse_limitパラメータで制御するようですね。あまり気にしてなかったので脳のしわが一つ増えた! defaultは、8 でOracleより多少、多いというところですね。
join_collapse_limit

 


perftestdb=> select version();
version
--------------------------------------------------------------------------------------------------------
PostgreSQL 13.6 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4), 64-bit
(1 行)

perftestdb=> show join_collapse_limit;
join_collapse_limit
---------------------
8
(1 行)

perftestdb=> \d+ master
テーブル"public.master"
列 | タイプ | 照合順序 | Null 値を許容 | デフォルト | ストレージ | 統計目標 | 説明
--------+-----------------------+----------+---------------+------------+------------+----------+------
id | integer | | not null | | plain | |
dummya | character varying(10) | | | | extended | |
インデックス:
"master_pkey" PRIMARY KEY, btree (id)
アクセスメソッド: heap

perftestdb=> \d+ detail
テーブル"public.detail"
列 | タイプ | 照合順序 | Null 値を許容 | デフォルト | ストレージ | 統計目標 | 説明
--------+-----------------------+----------+---------------+------------+------------+----------+------
id | integer | | not null | | plain | |
subid | integer | | not null | | plain | |
dummya | character varying(10) | | | | extended | |
インデックス:
"pk_detail" PRIMARY KEY, btree (id, subid)
アクセスメソッド: heap

perftestdb=> analyze verbose master;
INFO: analyzing "public.master"
INFO: "master": scanned 1 of 1 pages, containing 10 live rows and 0 dead rows; 10 rows in sample, 10 estimated total rows
ANALYZE
perftestdb=> analyze verbose detail;
INFO: analyzing "public.detail"
INFO: "detail": scanned 1 of 1 pages, containing 20 live rows and 0 dead rows; 20 rows in sample, 20 estimated total rows
ANALYZE
perftestdb=>

 

では試してみましょう。


perftestdb=> \timing on
タイミングは on です。
perftestdb=>
perftestdb=>
perftestdb=> \i ./test1_pg.sql
QUERY PLAN
-----------------------------------------------------------------------------------------------
Hash Join (cost=19.53..156.40 rows=10240 width=116)
Hash Cond: (master.id = t8.id)
-> Hash Join (cost=12.93..31.40 rows=1280 width=83)
Hash Cond: (master.id = detail.id)
-> Hash Join (cost=6.33..10.00 rows=160 width=50)
Hash Cond: (master.id = t4.id)
-> Hash Join (cost=2.67..4.45 rows=40 width=28)
Hash Cond: (master.id = t7.id)
-> Hash Join (cost=1.23..2.50 rows=20 width=17)
Hash Cond: (t6.id = master.id)
-> Seq Scan on detail t6 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=1.10..1.10 rows=10 width=6)
-> Seq Scan on master (cost=0.00..1.10 rows=10 width=6)
-> Hash (cost=1.20..1.20 rows=20 width=11)
-> Seq Scan on detail t7 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=3.15..3.15 rows=40 width=22)
-> Hash Join (cost=1.45..3.15 rows=40 width=22)
Hash Cond: (t4.id = t5.id)
-> Seq Scan on detail t4 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=1.20..1.20 rows=20 width=11)
-> Seq Scan on detail t5 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=5.60..5.60 rows=80 width=33)
-> Hash Join (cost=2.90..5.60 rows=80 width=33)
Hash Cond: (detail.id = t3.id)
-> Hash Join (cost=1.45..3.15 rows=40 width=22)
Hash Cond: (detail.id = t2.id)
-> Seq Scan on detail (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=1.20..1.20 rows=20 width=11)
-> Seq Scan on detail t2 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=1.20..1.20 rows=20 width=11)
-> Seq Scan on detail t3 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=5.60..5.60 rows=80 width=33)
-> Hash Join (cost=2.90..5.60 rows=80 width=33)
Hash Cond: (t8.id = t10.id)
-> Hash Join (cost=1.45..3.15 rows=40 width=22)
Hash Cond: (t8.id = t9.id)
-> Seq Scan on detail t8 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=1.20..1.20 rows=20 width=11)
-> Seq Scan on detail t9 (cost=0.00..1.20 rows=20 width=11)
-> Hash (cost=1.20..1.20 rows=20 width=11)
-> Seq Scan on detail t10 (cost=0.00..1.20 rows=20 width=11)
(41 行)

時間: 29.117 ミリ秒
perftestdb=>

 

MySQLで上限を制限した時間と似たような時間でパースが行われていますね。ただ、HASH JOINが選択されていますがw この辺りも、MySQLの生い立ちと、PostgreSQL、そしてOracleの違いとして現れてきます。MySQL 8のHash Joinって、MySQL 8.0.20 でHASH JOINが効くケースが拡大したという元々、Block Nested Loopの置き換えとしての意味が強かったという生い立ちが影響しているようにも見えます。なので、等価結合のINNER JOIN(今回の例)の場合、MySQL 8.0.32でもNLJが選択されているということのようですね。似てるようで似てないRDBMSの世界。まだまだ、私も学びが必要ですね。ちょっと曲のあるMySQLのHash Joinの発動条件。。いずれPostgreSQLやOracleっぽくHash Joinをカジュアルに使えちゃう日が来るのだろうか。。。

 

最後に真打w Oracle Database

 

今回は、23c Freeで試します。ただし、前回のエントリーにあるように、23c freeでは、"_optimizer_max_permutations" = 300と少なく設定されています。
今回の確認では、正式リリースされれば、通常の 2000 になるだろう。という想定で、 2000 にしてハードパース時間を確認しておきます。


SCOTT@freepdb1> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release

 

デフォルトの設定はいかですが、.sqlスクリプト内で、 _optimizer_max_permutations を 2000 に設定して実行します!


parameter name                   parameter value
-------------------------------- ------------------------------
_optimizer_max_permutations 300
_optimizer_search_limit 5


SCOTT@freepdb1> desc master
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
DUMMYA VARCHAR2(10)

SCOTT@freepdb1> desc detail
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
SUBID NOT NULL NUMBER
DUMMYA VARCHAR2(10)

SCOTT@freepdb1> select table_name,index_name,column_name from user_ind_columns where table_name in ('MASTER','DETAIL') order by table_name,index_name,column_position;

TABLE_NAME INDEX_NAME COLUMN_NAME
------------------------------ ------------------------------ ------------------------------
DETAIL PK_DETAIL ID
DETAIL PK_DETAIL SUBID
MASTER SYS_C008265 ID

SCOTT@freepdb1> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'MASTER',cascade=>true,no_invalidate=>false);

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

経過: 00:00:01.08
SCOTT@freepdb1> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'DETAIL',cascade=>true,no_invalidate=>false);

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

経過: 00:00:00.13

では、試してみましょう!


SCOTT@freepdb1> @test1_ora

セッションが変更されました。

経過: 00:00:00.01

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_optimizer_max_permutations integer 2000
1* alter system flush shared_pool

システムが変更されました。

経過: 00:00:00.68

解析されました。

経過: 00:00:00.27

 

一般的なOracleの_optimizer_max_permutationsパラメータの設定で、 0.27 sec となりました. こんなもんでしょうね。- this is an adaptive plan となっているので、ACTUAL PLANを見ないと確定できないケースですが、多分
Hash joinが選ばれていることでしょうw(なので確認まではしませんが)

 

ついでなので、実行計画(見積もり)を見ておきましょう。 hash joinになってますね。一部、SORT MERGE JOINになってますが、


SCOTT@freepdb1> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------
Plan hash value: 3620033460

-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10240 | 950K| 33 (4)| 00:00:01 |
|* 1 | HASH JOIN | | 10240 | 950K| 33 (4)| 00:00:01 |
| 2 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
|* 3 | HASH JOIN | | 5120 | 430K| 30 (4)| 00:00:01 |
| 4 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
|* 5 | HASH JOIN | | 2560 | 192K| 27 (4)| 00:00:01 |
| 6 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
|* 7 | HASH JOIN | | 1280 | 87040 | 24 (5)| 00:00:01 |
| 8 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
|* 9 | HASH JOIN | | 640 | 37760 | 21 (5)| 00:00:01 |
| 10 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
|* 11 | HASH JOIN | | 320 | 16000 | 18 (6)| 00:00:01 |
| 12 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
|* 13 | HASH JOIN | | 160 | 6560 | 15 (7)| 00:00:01 |
|* 14 | HASH JOIN | | 80 | 2560 | 12 (9)| 00:00:01 |
|* 15 | HASH JOIN | | 40 | 920 | 9 (12)| 00:00:01 |
| 16 | MERGE JOIN | | 20 | 280 | 6 (17)| 00:00:01 |
| 17 | TABLE ACCESS BY INDEX ROWID| MASTER | 10 | 50 | 2 (0)| 00:00:01 |
| 18 | INDEX FULL SCAN | SYS_C008265 | 10 | | 1 (0)| 00:00:01 |
|* 19 | SORT JOIN | | 20 | 180 | 4 (25)| 00:00:01 |
| 20 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
| 21 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
| 22 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
| 23 | TABLE ACCESS FULL | DETAIL | 20 | 180 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------


Note
-----
- this is an adaptive plan

174行が選択されました。

経過: 00:00:00.71

MySQL/PostgreSQL/Oracleそれぞれ、ハードパースの結合順評価テーブル数上限にも癖というか違いがあって、かつ、それが、パース時間の差になってみたり。癖が多いですよね。それぞれの特徴というか。
ついでに、実行計画、MySQLのHash Joinの発動ケース。現状OracleやPostgreSQLのようには使えないので、その辺りは、認識しておいた方が良いですよね。癖として ;)

8月末に東北に居たのですが、例年だと朝晩は涼しくて、過ごしやすいのに、今年は、ダメですね。東京と同じです。農作物への影響が気になりますね。寒暖の差が美味しさに影響するのもありますからね。。。

 

では、また。

 

次回は、OracleのSQLヒントネタでもしようかと思ってます。Oracleのヒントレポートが出力されるようになって、そこ気になる、なぜ。みたいな方も多かったり、それにより無用な議論があったりと聞いているのでw 一応書いておこうかなと。

 



MySQL/PostgreSQL/Oracleで利用したスクリプト(テーブル、索引定義およびデータ取得と統計取得コマンドは本文参照のこと)

MySQL


[master@localhost ~]$ cat test1.sql
use perftestdb;


explain
select *
from
master inner join detail
on master.id = detail.id
inner join detail t2
on
t2.id = detail.id
inner join detail t3
on
t3.id = t2.id
inner join detail t4
on
t4.id = t3.id
inner join detail t5
on
t5.id = t4.id
inner join detail t6
on
t6.id = t5.id
inner join detail t7
on
t7.id = t6.id
inner join detail t8
on
t8.id = t7.id
inner join detail t9
on
t9.id = t8.id
inner join detail t10
on
t10.id = t9.id
;

 

PostgreSQL


[master@localhost ~]$ cat test1_pg.sql
explain
select *
from
master inner join detail
on master.id = detail.id
inner join detail t2
on
t2.id = detail.id
inner join detail t3
on
t3.id = t2.id
inner join detail t4
on
t4.id = t3.id
inner join detail t5
on
t5.id = t4.id
inner join detail t6
on
t6.id = t5.id
inner join detail t7
on
t7.id = t6.id
inner join detail t8
on
t8.id = t7.id
inner join detail t9
on
t9.id = t8.id
inner join detail t10
on
t10.id = t9.id
;

 

Oracle


[master@localhost ~]$ cat test1_ora.sql
alter session set "_optimizer_max_permutations"=2000;
show parameter "_optimizer_max_permutations"

alter system flush shared_pool
.
l
/


explain plan for
select *
from
master inner join detail
on master.id = detail.id
inner join detail t2
on
t2.id = detail.id
inner join detail t3
on
t3.id = t2.id
inner join detail t4
on
t4.id = t3.id
inner join detail t5
on
t5.id = t4.id
inner join detail t6
on
t6.id = t5.id
inner join detail t7
on
t7.id = t6.id
inner join detail t8
on
t8.id = t7.id
inner join detail t9
on
t9.id = t8.id
inner join detail t10
on
t10.id = t9.id
;

 



関連エントリー
Oracle Database 23c Free Developer Releaseの”_optimizer_max_permutations” parameterの設定値について

 


標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)
標準はあるにはあるが癖の多いSQL 全部俺 #11 デュエル、じゃなくて、デュアル
標準はあるにはあるが癖の多いSQL 全部俺 #12 文字[列]探すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #13 あると便利ですが意外となかったり
標準はあるにはあるが癖の多いSQL 全部俺 #14 連番の集合を返すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #15 SQL command line client
標準はあるにはあるが癖の多いSQL 全部俺 #16 SQLのレントゲンを撮る方法
標準はあるにはあるが癖の多いSQL 全部俺 #17 その空白は許されないのか?
標準はあるにはあるが癖の多いSQL 全部俺 #18 (+)の外部結合は方言
標準はあるにはあるが癖の多いSQL 全部俺 #19 帰ってきた、部分文字列の扱いでも癖w
標準はあるにはあるが癖の多いSQL 全部俺 #20 結果セットを単一列に連結するにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #21 演算結果にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #22 集合演算にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #23 複数行INSERTにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #24 乱数作るにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #25 SQL de Fractalsにも癖がある:)
標準はあるにはあるが癖の多いSQL 全部俺 おまけ SQL de 湯婆婆やるにも癖がでるw
帰ってきた! 標準はあるにはあるが癖の多いSQL #1 SQL de ROT13 やるにも癖が出るw帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出る

| |

コメント

コメントを書く