CodeGym /コース /SQL SELF /プラン解析によるクエリ最適化: EXPLAIN ANALYZE

プラン解析によるクエリ最適化: EXPLAIN ANALYZE

SQL SELF
レベル 42 , レッスン 0
使用可能

ここが本番だよ:SQLクエリってただのコードの一行じゃなくて、データベースとの本気の会話なんだ。もし優しく"SELECT *"って囁けば、データベースは素直に理解してコマンドを実行してくれる。でも、構造化されてないSQL小説を投げつけたら、データベースは「え?」ってなって…そして遅くなる。

クエリ最適化は、データベースと分かりやすく簡潔な言葉で話すスキル。クエリが明確で効率的なら、実行も速いし、システムに負荷もかけないし、他のプロセスの邪魔にもならない。でも、イケてないクエリだとシステム全体が遅くなる:CPUやメモリを無駄に食うし、ディスクも余計な読み書きで忙しくなるし、データベースを使うアプリもモッサリしちゃう。

EXPLAIN ANALYZEは、そんな問題のある部分を見つけて、「どこでクエリが重くなってるか」を教えてくれる。まるで診断ツールみたいなもので、これがないとパフォーマンス改善は難しい。

クエリでよくある問題とその見つけ方

じゃあ、パフォーマンスを悪くする「容疑者」たちを紹介しよう。そのためにEXPLAIN ANALYZEコマンドを使うよ。

問題1: シーケンシャルスキャン (Seq Scan)

Seq Scan(シーケンシャルスキャン)は、PostgreSQLがテーブルの全行を1つずつ見てデータを探すこと。テーブルが小さいならいいけど、大きいとこれは地獄。

Seq Scanが使われてるかどうかを知るには? EXPLAIN ANALYZEで分析してみよう。例:

EXPLAIN ANALYZE
SELECT * 
FROM students 
WHERE student_id = 123;

結果はこんな感じ(Seq Scanに注目):

Seq Scan on students  (cost=0.00..35.50 rows=1 width=72) (actual time=0.010..0.015 rows=1 loops=1)

どうやって解決する?

student_idにインデックスがなければ作ろう:

CREATE INDEX idx_student_id ON students(student_id);

その後、もう一度EXPLAIN ANALYZEを実行。今度はSeq ScanじゃなくてIndex Scanが出るはず。

問題2: 条件の選択性が低い

選択性っていうのは、目的のデータを見つけるために何行処理しなきゃいけないかってこと。もしフィルターがほぼ全テーブルをカバーしてたら、インデックスは役に立たない。

選択性が低いクエリの例:

EXPLAIN ANALYZE
SELECT * 
FROM students 
WHERE program = 'Computer Science';

もしテーブルの90%の学生がComputer Science専攻なら、インデックスがあってもSeq Scanになることがある。

クエリをどう改善する?

  1. クエリのロジックを見直そう:もしかしたら、もっと条件を追加してフィルターを絞れるかも。
  2. テーブルの統計情報が最新か確認しよう(これでPostgreSQLが選択性を正しく判断できる):
ANALYZE students;
  1. もしクエリが不必要にインデックスじゃなくてシーケンシャルスキャンを使ってたら、PostgreSQLにインデックスを使わせるようにしてみよう:
SET enable_seqscan = OFF;

問題3: 無駄なソート処理

ソート(Sort)は結構コストが高い操作。特にデータがメモリに収まらないときはヤバい。典型的なのはORDER BYを使う場合。

問題の例:

EXPLAIN ANALYZE
SELECT * 
FROM students
ORDER BY last_name;

こんな感じの結果が出るかも:

Sort  (cost=123.00..126.00 rows=300 width=45) (actual time=1.123..1.234 rows=300 loops=1)

どうやってソートを速くする? 特定のカラムでよくソートするなら、インデックスを作ろう:

CREATE INDEX idx_last_name ON students(last_name);

これでPostgreSQLはインデックスを使って、データをソート済みで取り出せるから、追加のソート処理を避けられる。

問題4: 制限(LIMIT)がない

SELECTで返す行数を制限しないと、必要なのが1行だけでもテーブル全体を処理しちゃうことがある。

こんな感じ:

EXPLAIN ANALYZE
SELECT * 
FROM students
WHERE gpa > 3.5;

もしデータベースに100万行あって、gpa > 3.5で80%がヒットしたら、かなり待たされるよ。

トップ10人だけ欲しいなら、LIMITを使おう:

SELECT *
FROM students
WHERE gpa > 3.5
ORDER BY gpa DESC
LIMIT 10;

さらに、LIMITOFFSETを組み合わせればページングもできる。

実行パラメータの管理: SET

PostgreSQLのSETコマンドは、セッションやクエリの動作パラメータを変更するために使う。これは一時的な設定で、今の接続だけに影響するんだ。

簡単に言うと、SETPostgreSQLの「気分」をその場で変える方法で、グローバル設定をいじらなくてもいい。

どんなときに使う?

  • レポート実行前に言語や日付フォーマットを変えたいとき。
  • 重いクエリだけメモリを増やしたいとき。
  • 大量データ投入時にログを一時的にオフにしたいとき。
  • 一時的にスキーマの検索パス(search_path)を変えたいとき。
  • セキュリティ管理(例えば一時的にユーザー権限を下げる)したいとき。

基本構文

SET パラメータ = 値;

今のパラメータ値を確認するには:

SHOW パラメータ;

デフォルト値に戻すには:

RESET パラメータ;

複合的な最適化の例

例えば、こんな課題があるとしよう:Computer Science専攻でGPAが高い順に最新の10人の学生を探したい。元のクエリはこう:

SELECT *
FROM students
WHERE program = 'Computer Science'
ORDER BY gpa DESC
LIMIT 10;
  1. クエリの分析: まずEXPLAIN ANALYZEを実行:

    EXPLAIN ANALYZE
    SELECT * 
    FROM students
    WHERE program = 'Computer Science'
    ORDER BY gpa DESC
    LIMIT 10;
    

    もしシーケンシャルスキャンやソートが出てきたら、最適化のサイン。

  2. フィルター&ソート用の複合インデックス:

    両方のカラムを含む複合インデックスを作ろう:

    CREATE INDEX idx_program_gpa
    ON students(program, gpa DESC);
    
  3. 改善の確認:

    もう一度EXPLAIN ANALYZEを実行。今度はこのインデックスが使われて、ソートやシーケンシャルスキャンが避けられてるはず。

クエリ最適化のやり方

  1. まずは今の実行プランを分析しよう。 EXPLAIN ANALYZEで問題のある操作を見つける。

  2. ボトルネックを特定しよう。 一番時間がかかってるノードやリソースを食ってる部分を探す。

  3. インデックスを作ろう。 どのカラムがフィルタやソートに使われてるか確認して、必要なインデックスを作成。

  4. データ量を最小限に。 LIMITOFFSET、そして正確なフィルタ条件を使おう。

  5. 統計情報を最新に。 ANALYZEを実行して、PostgreSQLがデータ分布をちゃんと把握できるように。

  6. 変更後はテスト! 最適化したらもう一度EXPLAIN ANALYZEでパフォーマンスが良くなったか確認しよう。

次はどうする?

これでクエリ最適化の超速コースは終了!おめでとう!EXPLAIN ANALYZEで色々試せば試すほど、PostgreSQLの中身がどんどん分かってくるよ。そして覚えておいて:どんな魔法のインデックスも、クエリが複雑すぎたり曖昧だったら助けてくれない。SQLも他の言語と同じで、分かりやすさが命!

2
タスク
SQL SELF, レベル 42, レッスン 0
ロック未解除
`EXPLAIN ANALYZE` の基本的な使い方
`EXPLAIN ANALYZE` の基本的な使い方
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION