言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

  1. トップページ
  2. SQL辞典
  3. EXPLAIN

EXPLAIN

対応: MySQL 拡張

クエリがどのように実行されるかを確認する命令です。インデックスの使用状況やパフォーマンス問題の調査に使います。

構文

クエリの実行計画を確認します(MySQL・PostgreSQL)。

EXPLAIN SELECT ...;

実際に実行して統計付きの実行計画を確認します(PostgreSQL・MySQL 8.0.18以降)。

EXPLAIN ANALYZE SELECT ...;

JSON形式で実行計画を確認します(MySQL)。

EXPLAIN FORMAT = JSON SELECT ...;

出力列の読み方(MySQL)

列名概要
idクエリ内のSELECT識別子です。サブクエリがある場合に複数の行が表示されます。
select_typeSELECT の種類を示します。SIMPLE(サブクエリなし)・SUBQUERY・DERIVED(FROM句サブクエリ)などがあります。
tableこのステップで参照しているテーブル名です。
typeテーブルへのアクセス方法です。const・ref・range・index・ALLの順に効率が下がります。
possible_keys利用できる可能性があるインデックスの一覧です。
key実際に使用されたインデックスです。NULL の場合はフルスキャンが行われています。
rowsスキャンが必要と推定される行数です。小さいほど効率的です。
Extra追加情報です。Using index(カバリングインデックス)・Using filesort(ソート処理)などが表示されます。

サンプルコード

以下の『members』テーブルを例に説明します。

members member_id name email status 1 孫悟空 goku@example.com active 2 ベジータ vegeta@example.com active 3 ブルマ bulma@example.com inactive 3 rows in set

基本的な実行計画を確認します。

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』を参照してください。クエリのパフォーマンスを根本から改善するには、適切なインデックス設計が重要です。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。