【テクニカル・上級編】 ヒストグラム統計 – PostgreSQL

統計情報の「解像度」をハックする:PostgreSQLにおけるヒストグラムの深淵

PostgreSQLのクエリプランナと長く付き合っていると、避けては通れないのが「統計情報」の不一致によるプラン崩壊だ。特に、`EXPLAIN ANALYZE`で見える「見積もり行数」と「実際の行数」の乖離が、なぜ起きるのか。その核心の一つに、`pg_stats`に鎮座する「ヒストグラム」の存在がある。

今日は、このヒストグラムという「不完全な地図」をどう読み解き、どう手懐けるべきかについて、少し深い話をしよう。

ヒストグラムは「概算」という名の妥協

PostgreSQLのヒストグラムは、等頻度バケット(Equi-depth histogram)として実装されている。全データをソートし、バケット数(デフォルトは`default_statistics_target`で制御される100)で均等に分割した境界値のリストだ。

ここで重要なのは、これが「全データの要約」であって、「全データの写し」ではないということだ。

例えば、ある列に100万行のデータがあり、バケット数が100なら、1バケットあたり1万行をカバーする。もし検索条件がそのバケットの境界線上にあった場合、プランナは線形補完によって行数を推測する。この「補完」が、複雑なデータ分布(例えば、特定の期間に集中する時系列データや、ロングテールな分布)に対して、いかに脆いか。我々はそこを常に意識しなければならない。

なぜ「見積もり」は外れるのか:境界値の呪い

多くのエンジニアが陥る罠は、`ANALYZE`の結果を過信することだ。

もし、あるカラムのデータがバケットの境界付近に偏っている場合、プランナは「その範囲内にはデータが均等に分布している」という甘い仮定を置く。しかし、現実は非情だ。バケット内で特定の極端な値にデータが集中していれば、プランナは数十倍、あるいは数百倍の誤差を平気で叩き出す。

特に注意が必要なのは、以下のケースだ。

  • 極端な偏り(Skew): 特定の値にデータが集中し、かつそれが境界をまたぐ場合。
  • 相関関係の欠如: `WHERE a = X AND b = Y` のように、列同士に相関がある場合。ヒストグラムは単一列の統計しか持たないため、これらが独立していると仮定して選択率を掛け合わせてしまう。

「解像度」を操作する:そのトレードオフ

「じゃあ、全テーブルの`statistics_target`を1000にすればいいじゃないか」と考えるのは早計だ。

統計ターゲットを上げることは、`ANALYZE`の負荷を増やし、カタログテーブル(`pg_statistic`)を肥大化させる。これはカタログに対するロック競合の要因にもなり得る。本当にチューニングすべきは、統計が必要な「特定のカラム」だけだ。

— 特定のカラムだけ解像度を上げる
ALTER TABLE orders ALTER COLUMN created_at SET STATISTICS 500;

このコマンドを打つべきなのは、「このカラムの範囲検索が、重いクエリのボトルネックになっており、かつデータの分布が非常に複雑である」と確信できた時だけだ。無闇な設定は、管理コストという負債を増やすだけである。

トラブルシューティングの勘所

もし本番環境で「なぜかインデックスを使わずにフルスキャンを選ぶ」という事象に遭遇したら、まず確認すべきは`pg_stats`だ。

1. `null_frac`と`n_distinct`: そもそも、データ分布の前提が崩れていないか。
2. `histogram_bounds`: 境界値が実際の検索範囲とどう重なっているか。
3. `correlation`: 物理的なデータ順序と値の順序の相関。これが低い場合、インデックススキャンはランダムI/Oの嵐となり、プランナはあえてシーケンシャルスキャンを選ぶことがある。

統計情報が古ければ、`ANALYZE`を打つのは基本中の基本だが、それでも直らない場合は、プランナが「ヒストグラムから読み取れる以上の情報」を必要としているサインだ。その時は、`CREATE STATISTICS`を使って列間の相関を明示的に学習させるか、あるいはクエリの書き方を工夫して、プランナにヒントを与える必要がある。

最後に:プランナと対話する

PostgreSQLのクエリプランナは優秀だが、魔法使いではない。与えられた統計情報という「地図」に基づいて、最もコストの低いルートを計算しているだけだ。

我々エンジニアの役割は、プランナを責めることではなく、プランナがより正確な決断を下せるように、統計情報の解像度を適切に制御し、必要であれば「地図」を補正してやることにある。

内部構造を理解し、データ分布の歪みを想像する。この感性こそが、泥臭いパフォーマンストラブルを解決する唯一の近道だ。皆さんのデータベースが、今日も最適なプランを選択し続けることを願っている。

コメント

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