目次
とある日
MySQL 8.0.32が1/17にGAされました。
リリースノートを見てて、気になった「explain_format
」について調べてた記録です。
MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.32 (2023-01-17, General Availability)
アップデート内容
サーバ変数に新しく「explain_format
」が追加されています。
EXPLAINしたときのフォーマットを定義できる変数です。
コマンドライン形式 | --explain-format=format |
---|---|
紹介された | 8.0.32 |
システム変数 | explain_format |
範囲 | グローバル、セッション |
動的 | はい |
SET_VAR ヒントが適用されます |
いいえ |
タイプ | 列挙 |
デフォルト値 | TRADITIONAL |
有効な値 | JSON``TREE``DEFAULT |
設定できる値は以下の値です。
TRADITIONAL
:ステートメントFORMAT=TRADITIONAL
の一部として指定されているかのように、MySQL の従来のテーブルベースの出力を使用します 。EXPLAIN
これは変数のデフォルト値です。JSON
: 指定されているかのように、JSON 出力形式を使用しFORMAT=JSON
ます。TREE
: 指定されているかのように、ツリーベースの出力形式を使用しFORMAT=TREE
ます。DEFAULT``TRADITIONAL
:まったく同じ効果 を持つことの同義語 。
普通にEXPLAINした場合。
(root@localhost) [test] 8.0.32 > explain select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: parent partitions: NULL type: range possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: NULL rows: 1 filtered: 100.00 Extra: Using where; Using index *************************** 2. row *************************** id: 1 select_type: SIMPLE table: child partitions: NULL type: ref possible_keys: par_ind key: par_ind key_len: 5 ref: test.parent.id rows: 1 filtered: 100.00 Extra: NULL 2 rows in set, 1 warning (0.00 sec)
今までTREE形式の場合は、formatで指定が必要でした。
(root@localhost) [test] 8.0.32 > explain format=tree select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=0.81 rows=1) -> Filter: (parent.id > 2) (cost=0.46 rows=1) -> Covering index range scan on parent using PRIMARY over (2 < id) (cost=0.46 rows=1) -> Index lookup on child using par_ind (parent_id=parent.id) (cost=0.35 rows=1)
今回のアップデートでexplain_formatで指定した形式によって出力してくれます。
(root@localhost) [test] 8.0.32 > set explain_format = tree; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test] 8.0.32 > explain select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=0.81 rows=1) -> Filter: (parent.id > 2) (cost=0.46 rows=1) -> Covering index range scan on parent using PRIMARY over (2 < id) (cost=0.46 rows=1) -> Index lookup on child using par_ind (parent_id=parent.id) (cost=0.35 rows=1) 1 row in set (0.00 sec)
地味ですが便利な変更ですね。
explain_format見比べ
(root@localhost) [test] 8.0.32 > select @@explain_format; +------------------+ | @@explain_format | +------------------+ | TREE | +------------------+ 1 row in set (0.00 sec)
TRADITIONAL
(root@localhost) [test] 8.0.32 > set explain_format = traditional; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test] 8.0.32 > select @@explain_format; +------------------+ | @@explain_format | +------------------+ | TRADITIONAL | +------------------+ 1 row in set (0.00 sec) (root@localhost) [test] 8.0.32 > explain select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: parent partitions: NULL type: range possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: NULL rows: 1 filtered: 100.00 Extra: Using where; Using index *************************** 2. row *************************** id: 1 select_type: SIMPLE table: child partitions: NULL type: ref possible_keys: par_ind key: par_ind key_len: 5 ref: test.parent.id rows: 1 filtered: 100.00 Extra: NULL 2 rows in set, 1 warning (0.00 sec)
JSON
(root@localhost) [test] 8.0.32 > set explain_format = json; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test] 8.0.32 > select @@explain_format; +------------------+ | @@explain_format | +------------------+ | JSON | +------------------+ 1 row in set (0.00 sec) (root@localhost) [test] 8.0.32 > explain select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "0.81" }, "nested_loop": [ { "table": { "table_name": "parent", "access_type": "range", "possible_keys": [ "PRIMARY" ], "key": "PRIMARY", "used_key_parts": [ "id" ], "key_length": "4", "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "0.36", "eval_cost": "0.10", "prefix_cost": "0.46", "data_read_per_join": "8" }, "used_columns": [ "id" ], "attached_condition": "(`test`.`parent`.`id` > 2)" } }, { "table": { "table_name": "child", "access_type": "ref", "possible_keys": [ "par_ind" ], "key": "par_ind", "used_key_parts": [ "parent_id" ], "key_length": "5", "ref": [ "test.parent.id" ], "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "cost_info": { "read_cost": "0.25", "eval_cost": "0.10", "prefix_cost": "0.81", "data_read_per_join": "16" }, "used_columns": [ "id", "parent_id" ] } } ] } } 1 row in set, 1 warning (0.00 sec)
TREE
(root@localhost) [test] 8.0.32 > set explain_format = tree; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test] 8.0.32 > select @@explain_format; +------------------+ | @@explain_format | +------------------+ | TREE | +------------------+ 1 row in set (0.00 sec) (root@localhost) [test] 8.0.32 > explain select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=0.81 rows=1) -> Filter: (parent.id > 2) (cost=0.46 rows=1) -> Covering index range scan on parent using PRIMARY over (2 < id) (cost=0.46 rows=1) -> Index lookup on child using par_ind (parent_id=parent.id) (cost=0.35 rows=1) 1 row in set (0.00 sec)
ANALYZE
(root@localhost) [test] 8.0.32 > explain analyze select * from parent join child on parent.id = parent_id where parent_id > 2 \G; *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=0.81 rows=1) (actual time=0.022..0.063 rows=1 loops=1) -> Filter: (parent.id > 2) (cost=0.46 rows=1) (actual time=0.014..0.040 rows=1 loops=1) -> Covering index range scan on parent using PRIMARY over (2 < id) (cost=0.46 rows=1) (actual time=0.012..0.038 rows=1 loops=1) -> Index lookup on child using par_ind (parent_id=parent.id) (cost=0.35 rows=1) (actual time=0.006..0.020 rows=1 loops=1) 1 row in set (0.00 sec)
DEFAULT
(TRADITIONALと同じだからこれなくてもいい気がする)
(root@localhost) [test] 8.0.32 > set explain_format = default; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test] 8.0.32 > select @@explain_format; +------------------+ | @@explain_format | +------------------+ | TRADITIONAL | +------------------+ 1 row in set (0.00 sec)
エラー
EXPLAIN ANALYZEでJSON形式は対応していないのでエラーになります。
MySQL :: MySQL 8.0 Reference Manual :: 13.8.2 EXPLAIN Statement
(root@localhost) [test] 8.0.32 > set explain_format = json; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test] 8.0.32 > explain analyze select * from parent join child on parent.id = parent_id where parent_id > 2 \G; ERROR 1235 (42000): This version of MySQL doesn't yet support 'EXPLAIN ANALYZE with JSON format' ERROR: No query specified
おまけ
ドキュメント見てて8.0.33に関する記述を見つけた。
MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.8.2 EXPLAIN ステートメント
MySQL 8.0.33 から、
EXPLAIN ANALYZE
およびの出力の数値はEXPLAIN FORMAT=TREE
、次の規則に従ってフォーマットされます。
0.001 ~ 999999.5 の範囲の数値は、10 進数として出力されます。
1000 未満の 10 進数の有効数字は 3 桁です。残りは 4 つ、5 つ、または 6 つです。
0.001 ~ 999999.5 の範囲外の数値は工学形式で出力されます。そのような値の例は
1.23e+9
、 および934e-6
です。末尾のゼロは出力されません。たとえば、
2.3
ではなく2.30
、では1.2e+6
なく を印刷します1.20e+6
。未満の数値
1e-12
は として出力され0
ます。
〆
個人的には、便利だと言われているTREE形式とか使わないでデフォルトでやるのであまり使わなさそうだなという感想です。