【テクニカル・上級編】 コスト定数設定 – PostgreSQL

プランナの「脳内」を書き換える:コスト定数チューニングの深淵

PostgreSQLのパフォーマンスに悩まされる夜、多くのエンジニアはまず`EXPLAIN ANALYZE`を叩き、インデックスの有無を確認し、`VACUUM`を検討するでしょう。しかし、それでもプランナが「なぜその非効率な計画を選んだのか?」と首を傾げたくなることはないでしょうか。

もし皆さんが、ハードウェアの特性を正確に把握しているにもかかわらず、PostgreSQLがまるで古いHDDを前提としたような古い計画を立て続けているなら……それは、`postgresql.conf`に眠るコスト定数たちが、現実の足元をすくっている証拠かもしれません。

今日は、プランナの「脳内コスト評価」を司るパラメータ、特に`seq_page_cost`と`random_page_cost`について、深掘りしていきましょう。

—

デフォルト値は「過去の亡霊」である

PostgreSQLのデフォルト値は、今となってはかなり保守的です。特に`random_page_cost = 4.0`という値。これは、ランダムアクセスがシーケンシャルアクセスよりも4倍コストがかかる、という前提に基づいています。

しかし、現代のNVMe SSDの世界において、この「4倍」という数字はあまりに隔絶しています。昨今のストレージ環境では、ランダムリードとシーケンシャルリードの速度差は限りなく1に近づいています。

プランナにとって、`random_page_cost`が高く設定されていることは、「インデックススキャンを避けてシーケンシャルスキャン(全件走査)を選べ」という強力な誘導尋問に他なりません。これこそが、メモリに乗り切るはずのデータに対して、なぜかフルスキャンが選択される「プランナの頑固さ」の正体です。

チューニングの哲学:単なる「数値合わせ」ではない

私が現場でよく行うチューニングの流儀を共有します。闇雲に値を弄るのではなく、まずはシステムが「何を重視しているか」を観察することから始めます。

  • `seq_page_cost` (デフォルト: 1.0)

基本的に私はこの値を基準点(1.0)として固定し、ここから他の値を相対的に調整します。

  • `random_page_cost` (SSD環境なら 1.1 〜 1.5)

SSD環境であれば、1.1から1.5程度まで下げてみてください。これにより、プランナはインデックススキャンに対して非常にポジティブになります。「ランダムアクセスはもはや悪ではない」とプランナに教え込む作業です。

ただし、注意が必要です。これらを変更すると、データベース全体の実行計画が「一斉に」変わる可能性があります。本番環境でいきなり値を変更するのは、爆弾の導火線に火をつけるようなものです。必ず`SET LOCAL`を使って、特定のセッションで実行計画がどう変化するかを確認する、あるいはステージング環境で検証を重ねる。これはエンジニアの基本であり、礼儀です。

パフォーマンストラブルシューティングの落とし穴

「コスト定数を下げれば速くなる」と信じ込むのは危険です。

コスト定数を下げすぎると、プランナは「インデックスを使えば低コストだ」と誤認し、結果として過剰なインデックススキャン(Nested Loopの多用など)を引き起こし、CPU負荷が急増するケースがあります。

特に、`random_page_cost`を極端に下げた際に遭遇しやすいのが、「意図しないNested Loopの誘発」です。Hash Joinが適しているはずの巨大な結合に対して、インデックススキャンを繰り返すコストの低いNested Loopを選択し、結果としてレスポンスタイムが著しく悪化する……この現象は、チューニングにおける典型的な「手痛いしっぺ返し」です。

最後に:プランナを信じすぎないこと

結局のところ、PostgreSQLのコストモデルは「概算」です。どれほど精密に`random_page_cost`を調整しても、プランナは統計情報(`pg_statistic`)という、常に過去の亡霊であるデータをもとに判断を下しています。

もし皆さんがチューニングの限界を感じているなら、パラメータを弄るだけでなく、`pg_stats`を覗き込み、ヒストグラムが実態と乖離していないかを確認してください。パラメータ調整は魔法ではありません。システムと対話し、データとハードウェアの特性をプランナに正しく翻訳するための、対話の手段なのです。

皆さんのデータベースが、今日も最適な実行計画を選択し、快適に駆動することを願っています。何か深淵なプランナの挙動を見つけたら、また語り合いましょう。

コメント

タイトルとURLをコピーしました