なぜPostgreSQLのプランナは「間違った道」を選ぶのか?コスト定数チューニングの勘所
現場でPostgreSQLをいじっていると、たまに遭遇するんですよね。「いや、そこはインデックス使ってくれよ!なぜフルスキャンなんだ!」と叫びたくなるようなクエリプラン。
`EXPLAIN ANALYZE`を叩いて、「コスト」という数字が並んでいるのを見ても、「これって結局、何基準で計算されているの?」と疑問に思ったことはありませんか?
今日は、PostgreSQLのオプティマイザが「どのルートが最速か」を判断するための頭脳である、コスト見積もりパラメータについて深掘りしてみましょう。ここを理解すると、DBエンジニアとしての「勘」が一段階鋭くなりますよ。
—
コスト見積もりの正体
PostgreSQLのプランナは、クエリを実行する前に「いくつかの実行計画」をシミュレーションし、最もコストが低いものを選びます。そのコスト計算のベースになっているのが、`postgresql.conf`にあるこれらの定数です。
- `seq_page_cost` (デフォルト: 1.0)
- `random_page_cost` (デフォルト: 4.0)
- `cpu_tuple_cost` (デフォルト: 0.01)
これらは「相対的な重み付け」です。例えば`random_page_cost`が4.0ということは、「ランダムアクセスはシーケンシャルアクセスの4倍のコスト(時間がかかる)」とプランナが想定していることを意味します。
なぜデフォルト値ではダメなことがあるのか?
ここが一番のポイントです。PostgreSQLのデフォルト値は、実は「HDD(回転する磁気ディスク)」を前提に設計されています。
HDDの場合、ランダムアクセス(シーク)は物理的にヘッドを動かす必要があるため、シーケンシャルアクセスより圧倒的に遅い。だから`random_page_cost`が4.0と高めに設定されています。
しかし、現代のインフラはどうでしょう? そう、SSDやNVMeですよね。
物理的なヘッド移動がないSSDでは、ランダムアクセスとシーケンシャルアクセスの速度差は、HDDほど大きくありません。
このギャップを放置すると、プランナは「ランダムアクセスは高いから、インデックスを引くよりテーブル全体をスキャンした方がマシだな」と誤認し、インデックスを無視し始めます。これが「なぜインデックスが使われないのか?」の代表的な原因の一つです。
—
実践:どう調整すべきか?
現場でよくあるのは、SSD環境なのに`random_page_cost`が高いままになっているケース。まずはこれを疑いましょう。
1. SSD環境なら値を下げる
SSDを使っているなら、`random_page_cost`を1.1〜2.0くらいまで下げてみるのが定石です。
— セッション単位で試すならこれでOK
SET random_page_cost = 1.1;
— EXPLAINでどう変わるか見てみる
EXPLAIN SELECT FROM users WHERE status = ‘active’;
これだけで、今までフルスキャン(Seq Scan)を選んでいたプランナが、インデックススキャン(Index Scan)を選んでくれるようになることが多々あります。
2. `cpu_tuple_cost` の微調整
`cpu_tuple_cost`は、1行を処理するコストです。大規模なテーブルを結合(JOIN)するクエリで、プランナがNested Loopを嫌ってHash Joinばかり選ぶようなら、ここを少し小さくするとバランスが変わることがあります。ただし、ここはかなり繊細なパラメータなので、むやみにいじると他のクエリが遅くなるリスクがあります。
—
注意:設定は「全体」に影響する
ここで一つ、先輩として釘を刺しておきます。これらのパラメータはグローバル設定です。
特定のクエリを速くするために`random_page_cost`を下げたら、他のクエリの実行計画まで変わり、全体としてパフォーマンスが落ちる……なんてことはザラにあります。
- まずは検証環境で試すこと。
- 特定のクエリだけが問題なら、パラメータをいじる前にインデックスの見直しや統計情報の更新(ANALYZE)を優先すること。
- それでもダメな時の「最後の手段」としてパラメータチューニングを使うこと。
これ鉄則です。
—
最後に
コストパラメータのチューニングは、いわば「プランナの価値観を今のハードウェアに合わせる作業」です。
「なぜこのプランナはこう動くのか?」と疑問を持ち、コスト定数に思いを馳せるようになれば、あなたも立派なデータベースエンジニアです。まずは現在の環境のディスク性能を想像して、`SHOW random_page_cost;` を叩くところから始めてみてください。
もし、設定を変えて劇的に速くなった時は、その感動を忘れないでくださいね。それがチューニングの醍醐味ですから。
それでは、また次回の記事でお会いしましょう!
コメント