【テクニカル・上級編】 統計ターゲット (default_statistics_target) – PostgreSQL

PostgreSQLの「統計ターゲット」を制する者が、クエリプランナを制す

PostgreSQLと長く付き合っていると、必ず一度は壁にぶち当たります。「なぜ、この単純なクエリでSeq Scanが選ばれるのか?」「なぜ、このインデックスを無視するのか?」と。

実行計画(EXPLAIN)を眺め、Cardinality(行数見積もり)の乖離に絶望する。そんなとき、多くのエンジニアはまずインデックスを疑い、あるいは `VACUUM ANALYZE` を叩いて祈ります。しかし、それでも改善しない場合、我々が目を向けるべきは、PostgreSQLの「脳」とも言える統計情報の精度、すなわち `default_statistics_target` です。

今日は、この設定が単なる「おまじない」ではなく、複雑なデータ分布を扱うための強力な武器であることを、少し深いレイヤーから掘り下げてみたいと思います。

—

統計ターゲットの正体:ヒストグラムの「解像度」

`default_statistics_target` が何をしているか、一言で言えば「データの分布をどれだけ細かく切り刻んで記録するか」ということです。

デフォルト値は `100` です。これは、`ANALYZE` 実行時に各列のデータを最大100個のバケット(区間)に分けてヒストグラムを作成することを意味しています。

しかし、考えてみてください。数百万行、数千万行のレコードが格納されたテーブルにおいて、わずか100個の「箱」だけで、データの偏りや不規則な分布を正確に表現できるでしょうか?

例えば、あるECサイトの注文テーブルで、「特定のキャンペーン期間だけ注文が急増する」といったデータ分布があるとします。この場合、100個のバケットでは、その急増したスパイクを正確に捉えきれず、プランナは「平均的な注文数」をベースにコストを算出してしまいます。結果として、Nested Loopが選択されるべきところでハッシュ結合が選ばれたり、インデックスが無視されたりするのです。

なぜ「闇雲に値を上げる」のは悪手なのか

よくあるミスとして、すべてのテーブルの統計ターゲットを一律で「1000」や「5000」に引き上げる運用が見受けられます。これは避けるべきです。

理由は二つあります。

1. ANALYZEのコスト爆増: 統計ターゲットを上げれば、その分だけCPUとI/Oを消費します。巨大なテーブルでターゲットを高く設定しすぎると、日次メンテナンスの `ANALYZE` が終わらなくなるリスクがあります。
2. プランナの計算コスト: 統計情報が肥大化すれば、クエリ解析(Parse/Analyze/Rewrite/Plan)のフェーズで、複雑なヒストグラムを読み解くコストも無視できなくなります。

統計ターゲットをいじるのは、「本当にプランナが誤解している列」だけに限定すべきです。

トラブルシューティング:どこを狙い撃つか

問題の特定は、`pg_stats` ビューを叩くことから始まります。

SELECT n_distinct, most_common_vals, histogram_bounds
FROM pg_stats
WHERE tablename = ‘orders’ AND attname = ‘order_date’;

ここで重要なのは `histogram_bounds` です。この値を見て、「データの分布が非常に複雑であるにもかかわらず、ヒストグラムが荒い」と直感したら、その列が犯人です。

特定の列だけ精度を上げたい場合は、グローバル設定をいじらずに以下のように個別設定します。

ALTER TABLE orders ALTER COLUMN order_date SET STATISTICS 500;

こうすることで、他の列には影響を与えず、この重要な列だけが高い解像度で統計が収集されるようになります。

経験から語る「注意点」

実運用で統計ターゲットを調整する際、忘れてはならないのが 「相関」の罠 です。

単一の列で統計ターゲットをどれだけ高めても、`WHERE a = 1 AND b = 2` のような複合条件における「相関」は、デフォルトの統計情報では完璧には解決できません。もし列間に強い相関があるなら、統計ターゲットをこねくり回すよりも、`CREATE STATISTICS` を使って「多変量統計」を定義する方が、遥かにクリーンで堅牢な解決策になります。

最後に:エンジニアとしての矜持

PostgreSQLのプランナは、我々が与えた統計情報という「地図」を頼りに、最短ルートを探し出します。もし地図の解像度が低ければ、当然、回り道をさせられてしまいます。

「クエリが遅い」と嘆く前に、一度 `pg_stats` を覗いてみてください。PostgreSQLがその列をどう認識しているかを知ることは、データベースエンジニアとしての解像度を上げることと同義です。

チューニングは魔法ではありません。統計の裏側にある「分布」という物理法則を理解し、適切に数値を制御する。この地道な積み重ねこそが、最高峰のパフォーマンスを支える唯一の道です。

皆さんのクエリが、今日も最適な実行計画を叩き出しますように。

コメント

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