「インデックスを貼ったのに遅い?」を卒業する。PostgreSQLのインデックスオンリースキャンを使いこなそう
「インデックスを貼ればクエリは速くなる」。これはデータベースエンジニアの基本中の基本ですよね。でも、実務でSQLをチューニングしていると、「インデックスをちゃんと使っているはずなのに、なぜか期待したほど速くならない」という壁にぶつかることはありませんか?
特に、何万、何百万というレコードを扱うテーブルで、少しでもレスポンスを削り出したいとき。そんな時に武器になるのが、今回紹介する「インデックスオンリースキャン(Index Only Scan)」です。
今日は、この「最強の最適化手法」の仕組みと、現場でどう意識して設計すべきか、少し深掘りしてみましょう。
—
1. なぜ「インデックス」だけでは足りないのか?
普通、PostgreSQLがインデックスを使ってデータを検索する流れはこうです。
1. インデックスを辿って、目的の行の「物理的な場所(ポインタ)」を見つける。
2. そのポインタを頼りに、テーブルの本体(ヒープ)まで行って、実際のデータを読み出す。
この「2. テーブルの本体を見に行く」という作業が、実は結構なコストなんです。特に大量の行をフェッチする場合、ディスクI/Oがボトルネックになってしまいます。
インデックスオンリースキャンは、文字通りこのステップを省きます。インデックスの情報だけでクエリを完結させる。つまり、テーブル本体を一度も見に行かない(=I/Oが発生しない)という、究極のショートカットなんです。
2. 鍵を握る「可視性マップ(Visibility Map)」の正体
ここで疑問に思うはずです。「インデックスには実データがないこともあるのに、どうやって中身を保証しているの?」と。
その答えが、PostgreSQLの可視性マップ(Visibility Map)です。
PostgreSQLは、あるページ(ブロック)内のすべての行が「全トランザクションから見て可視である(最新である)」ことを知っています。この情報を管理しているのが可視性マップです。
もしインデックスに欲しいカラムが含まれていて、かつ可視性マップを見て「このページ内のデータはみんな最新だよね」と確認できれば、わざわざヒープを見に行かなくても、インデックスのデータだけでクエリを確定できる。これがインデックスオンリースキャンの仕組みです。
3. 実践:インデックスオンリースキャンを狙い撃つ
理屈はわかったところで、どうやって設計に落とし込むか。一番簡単なのは「INCLUDE句」の活用です。
例えば、ユーザーのメールアドレスとステータスを頻繁に検索するようなケースを考えてみましょう。
— よくあるクエリ
SELECT email FROM users WHERE status = ‘active’;
単に `status` にインデックスを貼るだけでは、`email` を取得するために結局ヒープを見に行きます。そこで、こうします。
CREATE INDEX idx_users_status_email ON users (status) INCLUDE (email);
こうすると、`status` で検索をかけつつ、インデックスの中に `email` のデータも埋め込まれるので、クエリはインデックスだけで完結します。これが「カバリングインデックス」という考え方ですね。
4. チューニングの注意点:VACUUMが鍵を握る
さて、ここで一つ、現場でハマりやすいポイントを伝授しておきます。
インデックスオンリースキャンは「可視性マップ」に依存しているため、データが頻繁に更新(UPDATE)されるテーブルだと、思ったように発動しないことがあります。更新直後は可視性マップが「まだ読み込まれていない」と判断されるためです。
もし「インデックスオンリースキャンが効かないな?」と思ったら、`VACUUM` が適切に走っているか確認してください。AutoVacuumの設定が甘いと、可視性マップが更新されず、この最適化が使われないケースは非常に多いです。
まとめ:エンジニアとして意識すべきこと
インデックスオンリースキャンは、魔法ではありません。
- SELECTするカラムを絞る: `SELECT ` を封印し、必要な列だけを指定する。
- カバリングインデックスを検討する: `INCLUDE` 句を使い、インデックスにデータを抱え込ませる。
- 運用を考える: VACUUMが正常に機能する環境を作る。
この3つを意識するだけで、あなたのクエリの実行計画(`EXPLAIN`)の表記は、`Index Scan` から `Index Only Scan` に華麗に変わるはずです。
データベースは嘘をつきません。仕組みを理解して設計してあげれば、必ずパフォーマンスで応えてくれます。皆さんの現場のクエリも、ぜひ一度 `EXPLAIN ANALYZE` してみてください。きっと、まだ削れる無駄が見つかるはずですよ。
それでは、また次回のチューニングでお会いしましょう!
コメント