なぜ「デフォルトのコスト定数」に頼り切ってはいけないのか?― `cpu_operator_cost` が変えるクエリの未来
PostgreSQLを長く触っていると、ある日突然、プランナが「明らかに間違った道」を選ぶ瞬間に出くわします。巨大なテーブルをフルスキャンする方が速いのに、わざわざコストの高いインデックススキャンを選んで泥沼にはまる。あるいは、Hash Joinでスマートに処理できるはずなのに、Nested Loopで永遠に計算が終わらない。
多くのエンジニアはここで `random_page_cost` を調整しようとします。もちろんそれも正解の一つですが、昨今の高速なNVMe SSD環境において、ボトルネックはI/Oだけでしょうか?
特に複雑な関数を多用するクエリや、巨大なJSONB型をパースしながら計算を行うようなワークロードでは、CPUの消費が支配的になります。ここで鍵を握るのが、あまり光の当たらないパラメータ `cpu_operator_cost` です。
—
`cpu_operator_cost` とは何か、その本質
PostgreSQLのプランナは、クエリの実行コストを「I/Oコスト」と「CPUコスト」の合計として算出します。`cpu_operator_cost` は、演算子や関数が実行されるたびにかかる単位コストを定義する定数です。
デフォルト値は `0.0025`。これは、`seq_page_cost`(デフォルト 1.0)を基準にした相対値です。つまり、プランナは「1ページ読み込むコストは、演算子400回分の重さがある」と見積もっているわけです。
しかし、考えてみてください。現代のCPUは非常に高速です。一方で、複雑な正規表現マッチングや、キャストを繰り返す計算、あるいはPostGISの空間演算はどうでしょうか? 1つの演算子が実行されるたびに発生する負荷は、単純な加算とは比較にならないほど重い。
ここが乖離のポイントです。プランナが認識している「CPU負荷」と、現実の「CPU消費」にズレが生じているとき、プランナはCPUリソースを過小評価し、不必要な計算を伴うプランを「安い」と勘違いして選んでしまうのです。
—
どんな時にこの設定を「いじる」べきか
僕がトラブルシューティングの現場でこのパラメータに手を出すのは、大抵こんな時です。
- 関数ベースのインデックスや、複雑なWHERE句がある場合
`WHERE func(col) = value` のようなクエリが多発し、かつ `func` が重い処理である場合、プランナは「関数呼び出しのコスト」を甘く見て、インデックスを無駄にスキャンしようとします。
- JSONBの深い階層へのアクセス
`->>` 演算子を多用するクエリで、Hash Joinが選択されるべきところでNested Loopが選ばれるなら、CPUコストを少し引き上げてみてください。プランナが「あ、この演算子は意外と重いんだな」と気づき、より効率的な集合処理プランを選択するようになります。
- 分析系クエリの並列処理
大量のデータに対して集計を行う際、`cpu_operator_cost` をわずかに上げることで、プランナが「並列クエリ(Parallel Query)を使ってタスクを分散した方が得だ」と判断しやすくなる傾向があります。
—
調整の作法:闇雲に触るな、計測せよ
この手のパラメータ調整で最もやってはいけないのは、勘で数値をいじることです。データベースエンジニアたるもの、エビデンスに基づきましょう。
1. まずは `EXPLAIN (ANALYZE, BUFFERS)` を徹底的に見ろ
「Actual Time」が「Cost」と乖離している演算子やノードを見つけます。特に、予想行数と実際の行数に差がないのに実行時間が異常に長い場合、それはCPUバウンドなノードである可能性が高いです。
2. セッションレベルで試す
全体設定を変える前に、`SET LOCAL cpu_operator_cost = 0.01;` のように実行中のトランザクションだけで試してください。これでプランが変わるか、実行時間が改善するかを確認します。
3. 魔法の数字はない
「0.01にすれば万事解決!」なんてことはありません。多くの場合、デフォルトの4倍〜10倍程度の間でスイートスポットが見つかることが多いですが、これはあくまでハードウェアの特性とクエリの複雑さに依存します。
—
最後に:プランナを「信じすぎる」な
PostgreSQLのコストモデルは非常に優秀ですが、あくまで「モデル」であり「現実」ではありません。特にモダンなアプリケーションでは、データベースが「単なるデータの箱」ではなく「高度な演算エンジン」として機能することが増えています。
`cpu_operator_cost` を調整するということは、プランナに対して「計算の重さ」を教え直すという高度なチューニングです。これを理解して使いこなせれば、あなたはPostgreSQLというエンジンの特性を、一段深いレイヤーから制御できるようになります。
さあ、皆さんのデータベースの実行計画は、本当に今のハードウェア性能を正しく理解できていますか? ぜひ `EXPLAIN` の向こう側を覗いてみてください。
コメント