【実務・中級編】 pg_statisticシステムカタログ – PostgreSQL

なぜクエリは突然遅くなるのか?「pg_stats」を味方につけて統計情報の裏側を覗こう

現場で働いていると、たまに「昨日まで爆速だったクエリが、今日になって突然フルスキャンを始めた……」なんていう冷や汗モノのトラブルに遭遇しますよね。

そんな時、真っ先に疑うべきは「統計情報の鮮度」です。PostgreSQLのオプティマイザ(プランナ)は、いわば「地図」を頼りに目的地(実行計画)を決める旅人です。その地図が古かったり、荒かったりしたら……そりゃあ迷子にもなりますよね。

今日は、その地図の「生データ」を覗き見る、PostgreSQLの心臓部の一つ『pg_statistic』と、その扱い方について少し深い話をしようと思います。

なぜ「pg_statistic」を直接触ってはいけないのか

まず、大前提の話をさせてください。PostgreSQLには `pg_statistic` というシステムカタログがありますが、これに直接 `SELECT` を投げるのはやめましょう。

理由は単純で、データが人間にとって絶望的に読みにくい形式(配列形式で、かつ型ごとにカラムが分かれている)で格納されているからです。

僕たちが普段使うべきは、そのラッパーである `pg_stats` ビュー です。これは `pg_statistic` の内容を人間が読みやすい形に整形してくれています。

— 自分のテーブルの統計情報をざっと確認する
SELECT
attname AS column_name,
n_distinct,
most_common_vals,
most_common_freqs
FROM pg_stats
WHERE tablename = ‘orders’;

これだけで、オプティマイザがそのカラムについて「どんな値がどれくらい頻繁に出現するか」をどう認識しているかが見えてきます。

現場で役立つ「統計情報の活用術」

僕がパフォーマンスチューニングをするとき、必ず見るポイントを3つ紹介します。

1. n_distinct(カーディナリティの把握)

`n_distinct` は「そのカラムにユニークな値がどれくらいあるか」を示しています。

  • 値が `-1` に近いなら、ほぼユニーク(主キーに近い)。
  • 値が小さいなら、重複が多いデータ。

もし、実際には100万種類の値があるカラムなのに、ここが極端に小さい数字になっている場合、オプティマイザは「この条件で絞り込めば少ししかヒットしないはずだ!」と誤解して、インデックスを使わずにフルスキャンを選ぶ……なんてミスを犯します。

2. most_common_vals (MCV)

「特定のフラグ値が異常に偏っている」ことはよくあります。例えば `status = ‘processed’` が全体の99%を占めているようなケースです。
`pg_stats` で `most_common_vals` を見れば、PostgreSQLが「どの値が頻出するか」をちゃんと把握しているか確認できます。もしここが空っぽなら、`ANALYZE` が足りていない証拠です。

3. histogram_bounds

範囲検索(`WHERE price > 1000` など)をする際、オプティマイザはヒストグラムを見て「何件くらいヒットするか」を推測します。ここが古いままだと、実際の件数と見積もりに大きな乖離(見積もり誤差)が生まれ、実行計画が崩壊します。

「統計情報がズレている」と気づいた時のアクション

もし、クエリの実行計画を見て「見積もり件数(rows)と実際の件数(actual rows)が全然違う!」となったら、迷わず手動で叩きましょう。

— 特定のテーブルの統計情報を強制更新
ANALYZE VERBOSE orders;

もし、それでも改善しない場合は、統計情報の精度(サンプリングサイズ) を疑ってください。PostgreSQLはデフォルトで「まあ、このくらいの量を見れば全体像はわかるだろう」とサンプリングして統計を作ります。データ分布が極端な場合は、これを上げてあげる必要があります。

— 統計情報の精度を上げる(デフォルトは0=自動)
ALTER TABLE orders ALTER COLUMN user_id SET STATISTICS 1000;
ANALYZE orders;

最後に:魔法の杖ではないけれど

統計情報のチューニングは、いわば「エンジンの調律」です。急激なデータ増加や、偏ったデータ投入が行われた時、PostgreSQLの自動 `ANALYZE` だけでは追いつかないことがあります。

`pg_stats` を眺める癖をつけておくと、「なぜこのクエリが遅いのか」を勘ではなく、根拠を持って説明できるようになります。これができると、一気にエンジニアとしてのレベルが一つ上がりますよ。

もし次にクエリが遅くなったら、まずは `pg_stats` を覗いてみてください。PostgreSQLが何を考えているのか、きっと教えてくれるはずです。

それでは、また現場で!

コメント

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