【実務・中級編】 統計ターゲット (default_statistics_target) – PostgreSQL

なぜPostgreSQLは「賢い選択」を間違えるのか?―統計ターゲットと向き合う現場の作法

「テスト環境では一瞬で終わるクエリが、本番の巨大テーブルを叩いた瞬間に数分かかるようになった」

エンジニアなら一度は経験する、この悪夢。PostgreSQLのクエリプランナは世界最高峰ですが、実は時々「思い込み」で盛大に空回りすることがあります。その原因の多くは、統計情報が現実のデータ分布と乖離していること、つまり「見ている地図が古すぎる(あるいは荒すぎる)」ことに起因します。

今日は、そんなトラブルを未然に防ぐための強力な武器、`default_statistics_target` について、現場の視点から掘り下げてみようと思います。

—

そもそも「統計ターゲット」って何者?

PostgreSQLはクエリを実行する前に、「どうやってデータを読み込むのが一番速いか」を計算します。その際、テーブルの各列がどのようなデータを持っているか(最大値、最小値、ヌル率など)をまとめた統計情報を参考にします。

ここで重要になるのが「ヒストグラム」です。分布が複雑な列に対して、PostgreSQLは「どの値がどのくらい含まれているか」を一定数のビン(バケット)に分けて記憶します。

この「ビンをいくつ作るか」を決める設定値、それが `default_statistics_target` です。

  • デフォルト値: 100
  • 役割: ANALYZEコマンドが統計情報を収集する際の「解像度」を決める

この数字を大きくすればするほど、より細かな粒度でデータの分布を把握できますが、その代わり統計情報の収集(ANALYZE)にかかる時間や、カタログテーブルのサイズが少しずつ肥大化していきます。

—

こんな時は「上げろ」のサイン

基本的にはデフォルトの100で十分です。しかし、以下のようなケースに直面したら、迷わずチューニングを検討してください。

1. 偏りの激しいカラム: 例えば「ステータス」列で、99%が「完了」で、残りの1%に多種多様なエラー状態が混在している場合。
2. JOINの結合条件: 結合キーの分布が独特で、プランナが「たった数行しか返ってこないはず」と見積もった結果、実際には数百万行が結合されてNested Loopが爆発するケース。

設定を変更する現場の手順

グローバルに設定を変えるのはおすすめしません。影響範囲が広すぎて、他のクエリのプランまで狂う可能性があるからです。「必要な列だけにピンポイントで適用する」のがプロの流儀です。

— 特定のカラムだけ統計ターゲットを上げる例
ALTER TABLE orders
ALTER COLUMN status SET STATISTICS 500;

— 反映させるために手動で統計を収集
ANALYZE orders;

こうすることで、その列のヒストグラムの粒度が上がり、プランナは「あ、この値は全体の0.1%しかないから、インデックスを引いた方が速いな」と、より正確な判断を下せるようになります。

—

現場で役立つ「見極め」のポイント

「統計ターゲットを上げれば全て解決!」というわけではありません。闇雲に数値を上げても、コストばかり増えて効果が出ないこともあります。

確認のためのステップ:
1. `EXPLAIN ANALYZE` でクエリを実行する。
2. 「Estimated Rows(見積もり行数)」と「Actual Rows(実際の行数)」を比較する。
3. この二つに巨大な乖離があれば、統計情報がズレている証拠。
4. `pg_stats` ビューを見てみる。

— 特定のカラムの統計情報を確認
SELECT n_distinct, most_common_vals, histogram_bounds
FROM pg_stats
WHERE tablename = ‘orders’ AND attname = ‘status’;

もし `histogram_bounds` がスカスカで、現実のデータ分布を全く表現できていないなら、`SET STATISTICS` の出番です。

—

注意点:銀の弾丸ではない

最後に一つだけ、釘を刺しておかなくてはいけません。
統計ターゲットを上げるのは、あくまで「データの分布が複雑な場合」の対処療法です。

もしクエリが遅い原因が「インデックスの貼り忘れ」や「SQLの書き方が悪い」のであれば、統計情報をいじっても本質的な解決にはなりません。まずは以下の順序で確認することをお勧めします。

1. インデックスは適切か?
2. 不要な全件検索(Seq Scan)を避ける書き方になっているか?
3. (ここで初めて)統計情報は正しいか?

—

まとめ

`default_statistics_target` は、PostgreSQLという優秀な相棒に「もっと現場の空気を読んでくれ」と教え込むための設定です。

最初は怖がらず、まずは影響の少ない開発環境や検証環境で、`ALTER TABLE … SET STATISTICS` を試してみてください。クエリプランが劇的に改善した時のあの感覚、エンジニアとして最高に気持ちいい瞬間ですよ。

何か詰まったら、いつでも聞いてくださいね。それでは、良いデータベースライフを!

コメント

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