CodeGym /コース /SQL SELF /EXPLAINって何?どうやってクエリを分析するの?

EXPLAINって何?どうやってクエリを分析するの?

SQL SELF
レベル 41, レッスン 2
使用可能

例えばアプリを開発してて、あるクエリが突然DBで一番重くなっちゃったとする。アプリが遅くなったり、エラーが出たりし始める。そんな時に登場するのがEXPLAIN。どこで問題が起きてるのかを教えてくれる。EXPLAINでクエリを分析して最適化すれば、リソース節約できるし、時間も短縮できるし、ユーザーの体験も良くなるよ。

EXPLAINは、PostgreSQLの中身を覗き見できるツール。DBがクエリをどう実行しようとしてるか見せてくれる。インデックスが使われるのか、全件スキャン(フルテーブルスキャン)になるのか、オプティマイザがどんな手順で何をするのか、中間結果がどれくらい大きいのか、全部わかる。

つまり、EXPLAINを使えばクエリ実行時に何が起きるか予想できる。「重い」クエリなのか、何行処理されるのか、どんなリソースが使われるのか。クエリが急に遅くなった時、「なぜ?」を調べるのに必須のツールだよ。

EXPLAINは暗闇の中の懐中電灯みたいなもの。中で何が起きてるか、どこで問題が起きてるか、ちゃんと見えるようになる。

EXPLAINコマンドの構文

まずはEXPLAINコマンドの基本構文を見てみよう:

EXPLAIN あなたの_SQL_クエリ;

クエリ例:

EXPLAIN SELECT * FROM students WHERE age > 20;

このコマンドを実行しても、PostgreSQLはクエリ自体は実行しない。その代わり、実行プランを見せてくれる。建設前の設計図みたいなもので、「壊す前に何が行われるか」確認できるのが便利。

出力例:

Seq Scan on students  (cost=0.00..35.00 rows=7 width=37)
  Filter: (age > 20)

この出力、最初はちょっと怖いかもだけど大丈夫。これから主要なパーツを解説するよ。

基本的な実行プランの読み方

さっきの結果を分解してみよう:

  1. Seq Scan on students — これはPostgreSQLがstudentsテーブルを全件スキャン(シーケンシャルスキャン)するって意味。必ずしも悪いわけじゃないけど、大きなテーブルだとSeq Scanは遅くなりがち。

  2. cost=0.00..35.00 — これは操作のコスト見積もり:

    • Startup Cost: 操作開始時のコスト(ここでは0.00)。
    • Total Cost: 操作完了までの合計コスト(ここでは35.00)。
  3. rows=7 — PostgreSQLはage > 20の条件で7行返すと予想してる。これを「カーディナリティ(cardinality)」って呼ぶ。変な値が出てたら、テーブルの統計情報が古いかも。

  4. width=37 — 1行あたりの平均バイト数。

  5. Filter: (age > 20) — PostgreSQLが各行にこのフィルタを適用するってこと。

こんな感じで、EXPLAINの出力からPostgreSQLの戦略や予想が見えてくる。この情報を使って最適化できるよ。

EXPLAINコマンドのオプション

基本のEXPLAIN出力も便利だけど、次のオプションでさらに詳しくできる:

ANALYZE

このオプションを付けると、PostgreSQLは実際にクエリを実行して、実データも出してくれる。例:

EXPLAIN ANALYZE SELECT * FROM students WHERE age > 20;

これで、PostgreSQLの予想と実際の実行結果を比べて、どれくらい合ってるか確認できる。

VERBOSE

もっと細かい情報が見たい時に使う。例:

EXPLAIN VERBOSE SELECT * FROM students WHERE age > 20;

BUFFERS

クエリ実行時のバッファ(メモリ)使用状況を表示。ANALYZEと一緒に使う:

EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM students WHERE age > 20;

COSTS

コスト情報(cost)を表示・非表示にできる:

EXPLAIN (COSTS OFF) SELECT * FROM students WHERE age > 20;

FORMAT

プラン出力をJSONやXMLなど他のフォーマットで表示できる。例:

EXPLAIN (FORMAT JSON) SELECT * FROM students WHERE age > 20;

EXPLAINの使い方例

universityデータベースにstudentsテーブルがあるとしよう。20歳より上の学生を探したい場合:

EXPLAIN SELECT * FROM students WHERE age > 20;

出力例:

Seq Scan on students  (cost=0.00..35.00 rows=7 width=37)
  Filter: (age > 20)

さっきも言ったけど、これはSeq Scan(全件スキャン)で、大きなテーブルだと効率悪いかも。

じゃあ、ageカラムにインデックスを作って、プランが変わるか見てみよう:

CREATE INDEX age_index ON students(age);

EXPLAIN SELECT * FROM students WHERE age > 20;

出力:

Index Scan using age_index on students  (cost=0.15..4.23 rows=7 width=37)
  Index Cond: (age > 20)

今度はPostgreSQLがインデックススキャン(Index Scan)を使ってる。大きなテーブルだとこっちの方が速いことが多い。

よくある質問とミス

インデックスがあるのにクエリが遅いのはなぜ?

クエリが返す行数が多すぎると、インデックス使ってもあまり意味がない場合がある。インデックス自体が古かったり、質が悪い場合もある。

EXPLAINの出力が難しすぎる時は?

まずはシンプルなクエリから始めて、実行プランのノードを一つずつ見ていこう。

テーブルの統計情報が古いかどうか知りたい時は?

ANALYZE studentsコマンドを実行しよう

ANALYZEなしでEXPLAINを使うのはいつ?

実際にクエリを実行したくない時(例えばデータを変更するクエリの場合)に使うといいよ。

2
タスク
SQL SELF, レベル 41, レッスン 2
ロック未解除
`EXPLAIN`とインデックスの利用
`EXPLAIN`とインデックスの利用
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION