EXPLAIN
| 対応: | MySQL 拡張 |
|---|
クエリがどのように実行されるかを確認する命令です。インデックスの使用状況やパフォーマンス問題の調査に使います。
構文
クエリの実行計画を確認します(MySQL・PostgreSQL)。
EXPLAIN SELECT ...;
実際に実行して統計付きの実行計画を確認します(PostgreSQL・MySQL 8.0.18以降)。
EXPLAIN ANALYZE SELECT ...;
JSON形式で実行計画を確認します(MySQL)。
EXPLAIN FORMAT = JSON SELECT ...;
出力列の読み方(MySQL)
| 列名 | 概要 |
|---|---|
| id | クエリ内のSELECT識別子です。サブクエリがある場合に複数の行が表示されます。 |
| select_type | SELECT の種類を示します。SIMPLE(サブクエリなし)・SUBQUERY・DERIVED(FROM句サブクエリ)などがあります。 |
| table | このステップで参照しているテーブル名です。 |
| type | テーブルへのアクセス方法です。const・ref・range・index・ALLの順に効率が下がります。 |
| possible_keys | 利用できる可能性があるインデックスの一覧です。 |
| key | 実際に使用されたインデックスです。NULL の場合はフルスキャンが行われています。 |
| rows | スキャンが必要と推定される行数です。小さいほど効率的です。 |
| Extra | 追加情報です。Using index(カバリングインデックス)・Using filesort(ソート処理)などが表示されます。 |
サンプルコード
以下の『members』テーブルを例に説明します。
基本的な実行計画を確認します。
sample_explain.sql
EXPLAIN SELECT name, email FROM members WHERE email = 'goku@example.com';
+----+-------------+---------+-------+--------------------------+--------------------------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+--------------------------+--------------------------+---------+-------+------+-------+ | 1 | SIMPLE | members | const | idx_members_email_unique | idx_members_email_unique | 1022 | const | 1 | | +----+-------------+---------+-------+--------------------------+--------------------------+---------+-------+------+-------+ 1 row in set
サブクエリを含むクエリの実行計画を確認します。
sample_explain.sql
EXPLAIN SELECT name, email FROM members WHERE member_id IN (SELECT member_id FROM members WHERE status = 'active');
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | members | ALL | NULL | NULL | NULL | NULL | 3 | Using where | | 2 | SUBQUERY | members | index | NULL | PRIMARY | 4 | NULL | 3 | Using where | +----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ 2 rows in set
JSON形式で詳細な実行計画を確認します(MySQL)。
sample_explain.sql
EXPLAIN FORMAT = JSON SELECT * FROM members WHERE status = 'active';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "0.45"
},
"table": {
"table_name": "members",
"access_type": "ALL",
"rows_examined_per_scan": 3,
"rows_produced_per_join": 3,
"filtered": "66.67",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.30",
"prefix_cost": "0.55",
"data_read_per_join": "8K"
},
"used_columns": ["member_id", "name", "email", "status"],
"attached_condition": "(`members`.`status` = 'active')"
}
}
}
1 row in set
実行計画と実際の実行統計を同時に確認します(MySQL 8.0.18以降)。
sample_explain.sql
EXPLAIN ANALYZE SELECT status, COUNT(*) AS cnt FROM members GROUP BY status;
-> Table scan on members (cost=0.55 rows=3) (actual time=0.028..0.035 rows=3 loops=1) -> Group aggregate: count(0) (cost=0.85 rows=3) (actual time=0.042..0.058 rows=3 loops=1) 1 row in set
データベース別の書き方
MySQL は『EXPLAIN』に加え、実際に実行して統計を取得する『EXPLAIN ANALYZE』が MySQL 8.0.18 以降で使用できます。
EXPLAIN SELECT name, email FROM members WHERE email = 'goku@example.com'; -- 実際に実行して統計を取得します(MySQL 8.0.18以降)。 EXPLAIN ANALYZE SELECT name, email FROM members WHERE email = 'goku@example.com';
PostgreSQL は『EXPLAIN』に加え、実際に実行して統計を取得する『EXPLAIN ANALYZE』が使用できます。
EXPLAIN SELECT name, email FROM members WHERE email = 'goku@example.com'; -- 実際に実行して統計を取得します(PostgreSQL)。 EXPLAIN ANALYZE SELECT name, email FROM members WHERE email = 'goku@example.com';
SQLite は『EXPLAIN QUERY PLAN』で簡易的な実行計画を確認できます。
EXPLAIN QUERY PLAN SELECT name, email FROM members WHERE email = 'goku@example.com';
概要
『EXPLAIN』の出力で最も重要な列は『type』と『key』です。『type』が『ALL』の場合はフルテーブルスキャン(全行走査)が発生しており、テーブルが大きいとパフォーマンスに直結します。『type』が『ALL』のときは WHERE 句の列にインデックスを追加することを検討してください。『key』に目的のインデックス名が表示されていればインデックスが使用されています。
『rows』は推定スキャン行数です。JOINを含むクエリでは各テーブルのrowsを掛け合わせた値が総スキャン量の目安になります。この値が大きい場合はインデックスの追加や、クエリの書き直しを検討しましょう。
インデックスの作成・削除は『CREATE INDEX』を参照してください。クエリのパフォーマンスを根本から改善するには、適切なインデックス設計が重要です。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。