隠れたコストの正体:`cpu_index_tuple_cost` がクエリプランを支配する仕組み
PostgreSQLのクエリプランナと日々対峙していると、時折「なぜオプティマイザは、明らかに効率的なインデックススキャンを選ばないのか?」という不可解な現象に遭遇することがある。統計情報は最新、相関(correlation)も悪くない。それなのに、なぜかシーケンシャルスキャンに逃げてしまう。
そんな時、多くのエンジニアは `random_page_cost` や `seq_page_cost` を疑う。もちろんそれらは重要だが、実はその裏で、より微細かつ決定的な影響を与えているパラメータがある。それが `cpu_index_tuple_cost` だ。
今日は、この「地味だが強力な」パラメータが、インデックススキャンのコスト見積もりにどう関与し、どんなパフォーマンストラブルを引き起こすのか、少し踏み込んで話をしようと思う。
—
cpu_index_tuple_cost とは何か?
PostgreSQLの公式ドキュメントには、「インデックススキャン中に各インデックスエントリを処理するためのコスト」とある。簡単に言えば、「インデックスのノードを1つ辿るたびに発生する、CPU的な負荷の重み付け」だ。
デフォルト値は `0.005`。これは、`cpu_tuple_cost`(タプル1件を処理するコスト、デフォルト0.01)よりも軽く設定されている。つまり、PostgreSQLは「テーブル上のタプルを直接触るよりも、インデックスを辿る方が(CPU負荷としては)コストが低い」という前提でコスト計算を行っているわけだ。
なぜ「インデックスの深さ」がコストを変えるのか
ここで注目すべきは、インデックスがB-tree構造であるという点だ。
インデックススキャンを行う際、クエリプランナはルートノードからリーフノードまで、インデックスの深さ(高さ)分だけノードを走査する必要がある。この「各ノードの通過コスト」の積み上げに、`cpu_index_tuple_cost` が掛け合わされる。
例えば、数十億行を超える巨大なテーブルを考えてみてほしい。インデックスの階層が深くなればなるほど、1つのインデックススキャンあたりの「CPUコスト」は増大する。
- インデックスの階層が深い場合: ノード走査の累積コストが無視できなくなる。
- インデックスの階層が浅い場合: 走査コストは相対的に低く見積もられる。
つまり、`cpu_index_tuple_cost` を調整するということは、単なる数値遊びではなく、「CPUがインデックスのツリー構造を深掘りすることに対して、どれだけのペナルティを与えるか」を定義することに他ならない。
—
パフォーマンストラブルシューティング:いつ、このパラメータを疑うべきか?
実務の現場でこのパラメータが問題になるのは、主に以下のようなシナリオだ。
1. インデックスが肥大化しているのに、プランナがインデックススキャンを過信している場合
インデックスのフラグメンテーションが進み、論理的な深さ以上にCPU負荷が高まっているケース。プランナはそれを正しく見積もれず、インデックススキャンを選択し続けることでCPUが枯渇する。
2. 高並列環境でのCPU競合
マルチコア環境で多数のセッションがインデックスツリーを頻繁に走査する場合、デフォルトの `0.005` が楽観的すぎることがある。この場合、インデックススキャンのコストをあえて高く見積もる(値を大きくする)ことで、より効率的な(あるいはシーケンシャルスキャンへの)計画を選択させることが、システム全体のCPU負荷抑制に繋がることがある。
チューニングの際の「禁じ手」と「流儀」
もちろん、これを安易に触るのは危険だ。`postgresql.conf` でグローバルに設定を変更するのは、まさに「劇薬」を投与するようなもの。
私がおすすめするのは、特定のセッションやトランザクション内での限定的な調整だ。
— 特定のクエリの実行直前に一時的に変更する
SET LOCAL cpu_index_tuple_cost = 0.01;
SELECT FROM huge_table WHERE …;
このように、特定のクエリに対してプランを強制的に「再評価」させるのが、熟練エンジニアの流儀ではないだろうか。
最後に:数値を追うのではなく、構造を追え
`cpu_index_tuple_cost` を理解することは、PostgreSQLというエンジンの「頭の中」を覗くことに似ている。オプティマイザがなぜそのルートを選んだのか、その背景にある「CPUコスト」という名の計算式に思いを馳せることで、クエリチューニングの精度は格段に上がるはずだ。
技術的に正しい解は、常にパラメータの先、そのアーキテクチャの根底にある。皆さんのデータベースが、今日も健やかに最適化されたプランで動き続けることを願っている。
それでは、また次回の深掘りでお会いしよう。
コメント