「PostgreSQLのプランナが、なぜあえて遅いクエリを選んでしまうのか?」
もしあなたが実務でそんな疑問を抱いたことがあるなら、今日のお話は間違いなく役に立つはずです。
PostgreSQLのクエリチューニングにおいて、多くの人が真っ先に手を出すのは `random_page_cost` や `seq_page_cost` ですよね。「ディスクI/Oを減らせば速くなる」という直感は正しい。でも、インデックスを適切に張っているのに、なぜかインデックススキャンが選ばれない、あるいは逆にインデックスを使いすぎてクエリが遅くなる……そんな「プランナの迷走」に悩まされたことはありませんか?
その犯人の一人が、今回紹介する `cpu_index_tuple_cost` です。
—
`cpu_index_tuple_cost` って何者?
簡単に言うと、これは「インデックスの各エントリを読み込む際にかかるCPUコスト」をプランナに教えるためのパラメータです。
PostgreSQLのクエリオプティマイザは、実行計画を立てる際、可能な限りコストの低いルートを探します。その計算式の中で、インデックスを使ってデータを絞り込むとき、「インデックスから1行ずつ取り出して評価するのに、これくらいのCPU負荷がかかるよね」と見積もるための重みがこれです。
デフォルト値は `0.005`。
この数値が意味するのは、「インデックス上の1タプルを処理するコストは、シーケンシャルスキャンで1ページ読み込むコスト(`seq_page_cost=1.0`)の200分の1だよ」という基準です。
なぜこの数値を気にする必要があるのか
結論から言うと、「インデックスの恩恵を過小評価(または過大評価)しているケース」があるからです。
例えば、メモリ(shared_buffers)が潤沢で、インデックスがほぼすべてメモリに乗っているような環境を想像してみてください。ディスクアクセスという概念が希薄な場合、プランナが考える「インデックススキャンのコスト」と、実際にクエリが動く時の「CPU処理の重さ」に乖離が生まれます。
また、複雑な条件や多段結合があるクエリでは、この微小なコストが積み重なり、プランナが「インデックスを使うより、テーブル全体をスキャンしたほうがマシだ」という誤った判断を下す引き金になることがあります。
—
実践:プランナに「もっとインデックスを信じろ」と伝える
例えば、特定のカラムで大量のインデックススキャンが発生しているのに、オプティマイザが全表スキャンを強行しようとする場合。まずは `EXPLAIN` でコストを見てみましょう。
— 現在のプランを確認
EXPLAIN ANALYZE SELECT FROM users WHERE status = ‘active’;
もし、インデックスを使っているのにコストが不当に高く見積もられていると感じたら、セッションレベルで一時的にコストを調整して、プランの変化を追ってみるのが定石です。
— インデックスのコストを少し下げてみる(実験的に)
SET cpu_index_tuple_cost = 0.001;
— 再度実行計画を確認
EXPLAIN ANALYZE SELECT FROM users WHERE status = ‘active’;
ここでの注意点:
この値をむやみに下げるのは禁じ手です。もし `0.0001` とか極端な値にすると、プランナは「インデックススキャンはタダだ!」と勘違いして、本来は全表スキャンしたほうが速いケースでもインデックスを選び続け、結果としてランダムアクセスが多発してパフォーマンスが崩壊します。
「微調整」が肝です。まずはデフォルト値から少しずつ(0.001単位で)動かして、実際の実行時間とプランの変化を観察してください。
—
現場の先輩からのアドバイス
実務でこの設定をいじる必要があるのは、「インデックスがメモリに完全に乗り切っているのに、プランナがディスクI/Oを過剰に見積もってインデックスを避けている」という、かなり限定的なケースが多いです。
もしあなたがクエリチューニングで行き詰まったら、まずは以下の順序で疑ってみてください。
1. 統計情報が古いのではないか? (`ANALYZE` を忘れていないか?)
2. インデックスの選択性が悪くないか? (WHERE句の条件で、テーブルの半分以上がヒットしていないか?)
3. `random_page_cost` は適切か? (SSDなのにデフォルトの4.0のままではないか?)
4. それでもダメなら… `cpu_index_tuple_cost` を疑う。
このパラメータは、いわば「プランナの性格」を調整する微調整ボルトです。闇雲に回すのではなく、「なぜプランナはこう考えたのか?」という理由を紐解くための材料として使ってみてください。
PostgreSQLのオプティマイザは非常に賢いですが、たまに環境の変化(ハードウェアの高速化など)についていけないことがあります。そんなとき、こういったパラメータを理解しているエンジニアが一人いるだけで、システムのパフォーマンスは劇的に変わります。
ぜひ、皆さんの環境でも `EXPLAIN` を叩いて、プランナが何を考えているのか、その「思考の跡」を覗いてみてくださいね。それでは、楽しいチューニングライフを!
コメント