コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB

EXPLAIN の読み方

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

EXPLAIN の読み方

このレッスンで分かること

  • MySQL の EXPLAIN の主要 6 列の意味
  • PostgreSQL の EXPLAIN ANALYZE の読み方
  • 「遅さの正体」を実行計画から見抜く手順

EXPLAIN の読み方 とは

MySQL / PostgreSQL の実行計画出力を実例で読み解く。本レッスンでは、EXPLAIN の読み方 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

MySQL の type 列 (アクセス方式) 完全早見表

type意味良し悪し典型シーン
system1 行のテーブル最良システムテーブル
constPRIMARY/UNIQUE で 1 行確定最良WHERE id = 5
eq_refJOIN で内側 1 行確定最良PK で JOIN
refインデックスで複数行普通のインデックススキャン
range範囲スキャンWHERE x BETWEEN ...
index全インデックススキャン注意カバリングなら OK
ALL全表走査危険インデックス未使用 = 設計ミス疑い

Extra 列で要注意のシグナル

Extra意味対策
Using indexカバリングインデックスそのまま (理想)
Using where追加フィルタ多くの行を絞っていれば許容
Using filesortメモリ/一時ファイルでソート複合インデックスにソート列を含める
Using temporary中間テーブル作成GROUP BY 設計を見直す

EXPLAIN の基本

EXPLAIN は SQL に付けるだけで「DBMS がどう実行する計画か」を表示してくれます。EXPLAIN ANALYZE (PostgreSQL) や EXPLAIN FORMAT=JSON (MySQL) で更に詳しい情報も取れます。

MySQL EXPLAIN の主要列

SQL クエリ

EXPLAIN SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE u.country = 'JP' AND o.status = 'paid';
idselect_typetabletypepossible_keyskeyrowsExtra
1SIMPLEurefidx_countryidx_country1000Using where
1SIMPLEorefidx_user,idx_statusidx_user8Using where

主要 6 列の意味は次の通りです。

id — クエリ内の SELECT 番号。サブクエリや UNION では複数の id が出る。

select_typeSIMPLESUBQUERYUNIONDERIVED などのクエリの種類。

table — 対象テーブル。

type最重要列。アクセス方式。良い順に system > const > eq_ref > ref > range > index > ALLALL は全表走査で、これが出たら危険信号。

key — 実際に使われたインデックス。NULL なら未使用。possible_keys には候補が出るが、実際選ばれたのは key の方。

rows — 読まれる推定行数。少ないほど良い。実際の行数とずれていたら統計情報が古い。

ExtraUsing index (カバリング)、Using where (フィルタ)、Using filesort (メモリ/一時ファイルでソート)、Using temporary (中間テーブル作成) など。Using filesortUsing temporary が出ているクエリは要注意。

type 列の見方

diagram (will load when visible)

実務では refrange が出れば合格、ALL が出たら設計ミスを疑います。

PostgreSQL の EXPLAIN

PostgreSQL は形式が違います。EXPLAIN だけでも見れますが、実行時間も知りたいなら EXPLAIN ANALYZE を使います(実際にクエリが走るので注意)。

プレーンテキスト

EXPLAIN ANALYZE SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE u.country = 'JP' AND o.status = 'paid'; Nested Loop (cost=0.85..1234.56 rows=80 width=64) (actual time=0.123..15.456 rows=72 loops=1) -> Index Scan using idx_country on users u (cost=0.42..345.67 rows=10 width=32) (actual time=0.045..1.234 rows=10 loops=1) Index Cond: (country = 'JP'::text) -> Index Scan using idx_user_status on orders o (cost=0.43..88.78 rows=8 width=32) (actual time=0.012..1.345 rows=7 loops=10) Index Cond: (user_id = u.id) Filter: (status = 'paid'::text) Planning Time: 0.234 ms Execution Time: 16.789 ms

ポイントを読み解きます。

  • cost=0.85..1234.56 — 開始コストと総コスト。プランナの推定値
  • rows=80 — 推定行数。actual rows=72 が実測値。乖離が大きいと統計が古い
  • actual time=... — 実測時間。最初の数字が「最初の行を返すまで」、2 つ目が「最後の行まで」
  • loops=10 — 内側の Index Scan が 10 回実行された(外側 10 行 × Nested Loop)

Nested Loop、Index Scan、Filter、Sort、Hash Join などのノードがツリー状に並びます。下から上に 読みます。

統計情報のズレを見抜く

rows=80 (推定) vs actual rows=8000 (実測) のように 100 倍ズレていたら、統計情報が古いか、複数カラムの相関が無視されています。

対策は次の 2 つです。

  • ANALYZE table_name で統計再計算
  • 複数カラムの相関には CREATE STATISTICS (PostgreSQL) を使う

EXPLAIN で 推定 vs 実測 がずれていたら、プランナの判断は信用できない。

よく出る問題パターン

1. type=ALL(全表走査)

インデックスを貼っていないか、貼っているが使われていない。WHERE の左辺に関数を使うとインデックスが効きません。

SQL クエリ

-- インデックスが効かない WHERE LOWER(email) = 'alice@ex.com' -- 関数インデックスを使うか、データ側を小文字化

2. Using filesort

ORDER BY がインデックスでカバーできていない。複合インデックスにソート列を含めると解消します。

3. Using temporary

GROUP BY で中間テーブルを作っている。インデックス順と一致しないと発生。

4. rows が極端に多い

絞り込み条件にインデックスが無いか、効きにくい条件。

やってみよう

  • 自分のプロジェクトのクエリを 3 つ取り出し、EXPLAINtype を確認する
  • type=ALL が出たクエリにインデックスを貼り、type=ref に変わるか確認
  • PostgreSQL なら EXPLAIN (ANALYZE, BUFFERS) でディスク I/O も観察する

まとめ

このレッスンの要点は、MySQL 主要 6 列 / PostgreSQL の actual time / 統計情報のズレ検出 の 3 点です。実務でこれらを切り分けて説明できるようになると、設計レビューや障害対応の精度が一段上がります。

理解度チェック

Q. MySQL EXPLAIN の type 列に ALL が出た。最初に疑うべきことは?

  1. サーバーのスペック不足
  2. WHERE 句に使うカラムにインデックスがない、または関数で隠されている
  3. クエリの構文エラー
  4. TCP コネクション数の上限
答えを見る

正解は 2type=ALL は全表走査。WHERE 条件にインデックスが効いていない (未作成、または LOWER(col)=... のように関数でインデックスが効かなくなっている) のが典型原因です。

出典 (References)

最終更新: 2026-05-28

関連レッスン

よくある質問

Q. このトピックは実務でどう役立ちますか?

A. DB のクエリ最適化、API 設計、データ構造の選択など、設計判断の根拠になります。表面的にライブラリを使うだけでなく「なぜそれが速いのか」を理解できると、性能問題を未然に防げます。コーディング面接でも頻出のテーマです。

Q. 計算量はどう求めれば良いですか?

A. ループのネストごとに掛け算する、再帰なら漸化式から解く、というのが基本です。Big-O 表記は定数倍と低次の項を無視するため、n の指数(n²、n log n など)に注目してください。最悪・平均・最良の 3 つを意識すると説得力が増します。

Q. 覚えるべき定番アルゴリズムは何ですか?

A. 二分探索、クイックソート/マージソート、BFS/DFS、ダイクストラ、DP の基本問題(フィボナッチ・ナップサック)が必修です。これらを「白紙から書ける」状態にすると、応用問題が一気に解けるようになります。

次のレッスン

次は Nested Loop / Hash / Merge Join で、MySQL / PostgreSQL の実行計画出力を実例で読み解く を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. EXPLAIN の読み方 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. EXPLAIN の読み方 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン