なぜ、あなたのPostgreSQLは「SSDをHDDだと思い込んでいる」のか?
PostgreSQLのチューニングにおいて、`random_page_cost`ほどエンジニアの経験と勘が試されるパラメータは他にないかもしれません。
デフォルト値の「4.0」。長年PostgreSQLを触っている方なら、一度は目にしたことがあるはずです。しかし、現代のNVMe SSDが当たり前の環境で、この「4.0」をそのまま放置しているとしたら……それはPostgreSQLに、「フェラーリに乗っているのに、時速40kmで走れ」と命じているようなものです。
今日は、なぜこのパラメータがクエリプランナの挙動を根本から変えてしまうのか、その内部アーキテクチャと実務的な最適化の勘所について、少し深く掘り下げてみたいと思います。
—
「random_page_cost」がプランナに与える影響
そもそも、`random_page_cost`は何を定義しているのか。これは「ランダムアクセスによるページ読み込みのコスト」です。シーケンシャルスキャン(`seq_page_cost`=1.0)を基準とし、それに対してランダムアクセスがどれだけ「高コストか」をプランナに伝えています。
ここで重要なのは、プランナは物理的な速度ではなく、この「コスト値」を元に実行計画を組み立てているという点です。
- 値が高い場合: プランナは「ランダムアクセスは遅い」と判断し、インデックススキャンを避け、シーケンシャルスキャンを優先します。
- 値が低い場合: プランナは「ランダムアクセスは十分に速い」と判断し、インデックスを使った効率的なネステッドループなどを積極的に選ぶようになります。
なぜSSD環境で「1.1」へ下げるのか
かつて機械式HDDの時代、シークタイムという物理的な制約が圧倒的でした。ランダムアクセスはシーケンシャルアクセスの数十倍、あるいはそれ以上のコストを要した。だからこそ「4.0」という値は理にかなっていたのです。
しかし、SSDの世界では話が別です。IOPSの桁が違います。私がモダンなDB設計を行う際は、迷わず `random_page_cost` を 1.1 に設定します(1.0にしないのは、それでもシーケンシャルアクセスの方がわずかに効率が良いという物理的現実を残しておくためです)。
これを行うと、これまでプランナが「コストが高い」として切り捨てていたインデックス・スキャンが、突然「最適解」として採用されるようになります。特に、バッファキャッシュに乗り切らない巨大なテーブルに対してクエリを投げる際、この変化は劇的です。
チューニングの落とし穴:理論と現実の乖離
ただし、ここからが現場の知恵です。「とりあえず1.1にすればいい」わけではありません。注意すべき点がいくつかあります。
1. 統計情報の鮮度:
`random_page_cost`を下げるとプランナは自信を持ってインデックスを使うようになります。しかし、`ANALYZE`が古く、統計情報が実態と乖離していたらどうなるか。誤ったインデックスを選択し、結果として膨大なランダムIOを発生させ、パフォーマンスが逆に悪化する「プランナの罠」に陥ります。
2. 実行計画の偏り:
特定のクエリだけがインデックスを多用するようになり、他のクエリとリソースの奪い合いを始めることもあります。特に並列クエリ(Parallel Query)と組み合わせる場合、プランナがシーケンシャルスキャンを選択しなくなることで、想定外の負荷がかかることもあります。
私がトラブルシューティングで見ているもの
もし、「クエリが遅い」という相談を受けたら、私はまず `EXPLAIN (ANALYZE, BUFFERS)` を叩きます。
ここで確認すべきは、「実際の実行時間」と「コストの乖離」です。Shared Hit(メモリ上のヒット)と Read(ディスクからの読み込み)の比率を見たとき、明らかにインデックス経由のReadが嵩んでいるにも関わらず、コスト見積もりが低すぎる場合。それはプランナが環境を過小評価している証拠です。
逆に、`random_page_cost`を下げてもなおシーケンシャルスキャンが選ばれるなら、それはもうパラメータの問題ではなく、テーブルの断片化や、インデックスそのものの有効性を疑うべきフェーズです。
—
最後に
`random_page_cost`を弄ることは、言わばPostgreSQLというエンジンの「点火タイミング」を調整するような作業です。
闇雲に変更するのではなく、まずは `EXPLAIN` で現在のコスト試算を見てください。そして、ストレージの特性と、実際のIO待機時間とを照らし合わせてみてください。その作業の積み重ねが、理論上のプランナと、物理的なハードウェアの間の「最適解」を導き出します。
DBエンジニアの仕事とは、結局のところ、データと機械の間の「翻訳」をどれだけ正確に行うか、ということなのかもしれませんね。
皆さんのPostgreSQLが、今日より少しだけ速く動くことを願っています。それでは。
コメント