「インデックスさえ貼れば正義」じゃない。PostgreSQLのシーケンシャルスキャンと正しく付き合う方法
「DBのパフォーマンスチューニング? とりあえずインデックスを貼ればいいんでしょ?」
後輩からこんな言葉を聞くと、思わず苦笑いしつつも「まあ、半分は正解だけどね」と答えたくなります。データベースエンジニアとして長く現場にいると、インデックスを「魔法の杖」のように崇拝するあまり、かえってクエリを遅くしてしまうケースを山ほど見てきました。
今日は、PostgreSQLの原点にして、避けては通れない「シーケンシャルスキャン(Seq Scan)」について、現場の視点から掘り下げてみようと思います。
シーケンシャルスキャンは「悪」ではない
まず、誤解を解いておきましょう。「Seq Scanが発生している=クエリが遅い=悪」という考え方は捨ててください。
PostgreSQLにとって、シーケンシャルスキャンはテーブルの全ページを最初から最後まで順番に読み込む、最もシンプルで力強いアクセス手法です。実は、ある程度のサイズまでのテーブルであれば、インデックスを使ってランダムアクセスを繰り返すよりも、シーケンシャルスキャンで一気にメモリに読み込んでしまった方が圧倒的に速いのです。
なぜPostgreSQLはSeq Scanを選ぶのか?
PostgreSQLのオプティマイザは、統計情報を基に「どのスキャンが最もコストが低いか」を常に計算しています。
例えば、テーブルの全行の90%を取得しようとするクエリに対して、インデックスを使おうとするとどうなるか。インデックスを辿ってページにアクセスし、また別のページへ……というランダムアクセスが頻発し、OSのディスクI/Oを激しく消耗します。
これなら、最初からテーブルを「全スキャン(Seq Scan)」して、メモリにキャッシュしながら処理した方が、総実行時間は短くなるわけです。つまり、Seq Scanが選ばれるということは、オプティマイザが「今のクエリには、これが一番効率的だ」と判断した結果なんですよ。
実践的な見極め方:EXPLAINの結果をどう読むか
例えば、こんな状況を想像してください。
EXPLAIN ANALYZE SELECT FROM users WHERE status = ‘active’;
これに対して、以下のような実行計画が返ってきたとします。
Seq Scan on users (cost=0.00..152.00 rows=5000 width=128) (actual time=0.02..2.10 rows=4800 loops=1)
Filter: (status = ‘active’)
Rows Removed by Filter: 200
ここで注目すべきは `cost` と `actual time` です。
もし `actual time` が許容範囲内なら、全く気にする必要はありません。逆に、ここが数秒単位でかかっているなら、「インデックスが足りない」のか、「統計情報が古くてオプティマイザが勘違いしている」のかのどちらかを疑います。
「Seq Scanを避けるべき」現場のシグナル
ただし、常に安全というわけではありません。以下のケースでは注意が必要です。
1. 巨大なテーブルへのフィルタリング:
数千万行あるテーブルに対して、特定の数行だけを探すのにSeq Scanが走っているなら、それはインデックスが使われていない(あるいは効いていない)サインです。
2. 統計情報の不整合:
`ANALYZE` を長期間実行していないと、PostgreSQLはテーブルのサイズを実際よりも小さく見積もってしまい、Seq Scanを選択し続けることがあります。
3. データ型の不一致:
インデックスを貼っていても、 `WHERE` 句でカラムの型と異なる比較(例:文字列カラムに対して数値で比較)を行うと、暗黙の型変換が走り、インデックスが無視されて強制的にSeq Scanになることがあります。
後輩へのアドバイス
「Seq Scanが出た!」と慌ててインデックスを追加する前に、まずは深呼吸して以下をチェックしてみてください。
- そのテーブル、本当に巨大ですか? 数百〜数千行なら、Seq Scanが最強です。
- クエリの対象行数はどれくらいですか? テーブル全体の大部分を読み込むなら、Seq Scanが最適解です。
- ANALYZEは最新ですか? 統計情報が古いと、オプティマイザは的確な判断ができません。
- 実行計画で「Index Scan」が選ばれない理由は? 型変換や、列に対する関数適用(`WHERE UPPER(name) = ‘TOM’` など)が邪魔をしていないか確認しましょう。
—
データベースを速くするコツは、魔法を探すことではなく、PostgreSQLという優秀なエンジンの考え方を理解してあげることです。Seq Scanは、彼らが懸命に働いている証拠。まずはその意図を読み解くところから始めてみてください。
さて、次は「インデックスを貼ってもSeq Scanから逃げられない時」の話でもしようかな。……それはまた、別の記事で。
コメント