データベースの「勘」を支配する場所:pg_statisticの深淵へ
PostgreSQLのクエリプランナが、なぜあんなにも鮮やかに実行計画を選び取れるのか。不思議に思ったことはありませんか? 複雑な結合条件や膨大なテーブルを前にしても、数ミリ秒で「最適なルート」を導き出すその裏には、必ずと言っていいほど彼らの「経験則」が詰まっています。
そう、それが `pg_statistic` です。
我々エンジニアが日々 SQL をチューニングする際、`EXPLAIN ANALYZE` を叩いてプランナと対話しますが、プランナが「なぜそのプランを選んだのか」を理解するには、このカタログが何をどう記録しているのかを知らなければ始まりません。今回は、PostgreSQL の心臓部とも言えるこの統計情報の深淵を、少し覗いてみましょう。
統計情報の「解像度」を理解する
`pg_statistic` は単なるデータの集まりではありません。プランナがコスト見積もり(Cost Estimation)を行うための「高次元の近似値」を格納する場所です。
まず押さえておきたいのは、ここに格納されているデータの形式です。例えば、`n_distinct`(列内の重複しない値の数)や `most_common_vals`(頻出値)といったカラムがありますが、これらは人間が直接 `SELECT` するために設計されたものではありません。そのため、`pg_statistic` を直接参照する際は、`pg_stats` ビューを通すのが一般的です。
しかし、シニアなエンジニアなら知っておくべきことがあります。`pg_statistic` にある `stakindN` と `stavaluesN` というカラム群です。これらは、PostgreSQL が統計情報を収集する際の「戦略」を保持しています。単なるヒストグラムだけでなく、MCV(Most Common Values)や相関値、最近では拡張統計情報による多列間の相関まで、ここで抽象化して管理されているのです。
なぜ、プランナは「嘘」をつくのか
現場でよく遭遇する「なぜ統計情報が最新なのに、プランナは全件スキャンを選択するのか?」というトラブル。その原因の多くは、この `pg_statistic` が捉えきれていない「データの分布の歪み」にあります。
- 相関の欠落: 複数の列にまたがる条件(例: `WHERE city = ‘Tokyo’ AND ward = ‘Shibuya’`)がある場合、デフォルトでは列ごとの統計情報を独立して扱い、積集合で確率を計算します。しかし、実際には強く相関していることが多く、ここでプランナは誤ったコスト見積もりを出します。
- ヒストグラムの粒度: デフォルトの統計収集粒度(`default_statistics_target`)では、データの分布が極端なロングテール(べき乗則に近い分布)を描いている場合、境界値付近の精度が著しく低下します。
こうした状況に陥ったとき、我々は「設定をいじればいい」と安易に考えがちですが、まずは `pg_statistic` が現在の分布をどう切り取っているのかを疑うべきです。特定の列に対して統計ターゲットを個別に引き上げる(`ALTER TABLE … ALTER COLUMN … SET STATISTICS`)のは、まさにこの「解像度」を上げる作業に他なりません。
現場で役立つチューニングの心得
パフォーマンストラブルシューティングにおいて、私が常に意識しているアプローチを共有します。
1. 「相関」を疑う: 複雑な WHERE 句でプランが跳ねる場合、`CREATE STATISTICS` を使って多列統計を作成してください。これは、`pg_statistic` の管理下に新しい「相関の定義」を書き込むのと同義です。
2. `ANALYZE` のタイミングと副作用: 手動で `ANALYZE` を実行することは強力な武器ですが、高負荷な環境では副作用も無視できません。統計情報の更新は、バックグラウンドワーカー(`autovacuum`)に任せるのが基本ですが、特定の列の分布が激しく変動するバッチ処理があるなら、その直後にピンポイントで `ANALYZE` を打つ設計にすべきです。
3. `pg_stats` の監視: 定期的に `null_frac` や `n_distinct` の推移を追うスクリプトを回しておくと、「いつの間にかデータ分布が変わっていた」という事態を未然に防げます。
最後に
`pg_statistic` は、PostgreSQL という巨大なエンジンが、外部の世界(我々が投入するデータ)をどう認識しているかを示す「世界地図」です。この地図が古ければ、どんなに優秀なクエリプランナも目的地にたどり着くことはできません。
データベースのチューニングとは、突き詰めれば「プランナという非常に賢い頭脳に、いかに正確な世界観(データ分布)を伝えるか」というコミュニケーションの問題です。
皆さんも、SQL が思うようなプランを選んでくれない時、一度 `pg_statistic` の視点に立ってみてください。そこには、機械的な数値の羅列ではなく、皆さんのアプリケーションが紡いできたデータの「生きた歴史」が刻まれているはずです。
コメント