【実務・中級編】 pg_statistic – PostgreSQL

「なぜかこのクエリだけ、急に遅くなるんだよな……」

現場でそんな悩みに直面したとき、実行計画(`EXPLAIN ANALYZE`)を見て、「よし、インデックスは効いてるな。あれ、でもなんでコストがこんなに高く見積もられてるんだ?」と首を傾げた経験はありませんか?

実は、PostgreSQLのクエリプランナが「どの道を通るのが一番速いか」を判断する際、唯一頼りにしているのが統計情報です。そして、その統計情報の心臓部こそが、今回深掘りするシステムカタログ`pg_statistic`です。

今日は、教科書には載っていない(というか、載っていても読み飛ばされがちな)「統計情報の裏側」について、実務的な視点から話してみようと思います。

—

1. pg_statsビューの「さらにその先」を見よう

皆さんが普段、手軽にデータの分布を確認するために使うのは`pg_stats`ビューですよね。
`SELECT FROM pg_stats WHERE tablename = ‘users’;` とか、よくやるはずです。

でも、ちょっと待ってください。`pg_stats`はあくまで人間が見やすいように加工された「読み取り専用ビュー」に過ぎません。その元データであり、プランナが直接脳みそとして使っているのが、システムカタログ`pg_statistic`です。

なぜわざわざ`pg_statistic`を意識する必要があるのか? それは、プランナが「何を勘違いしているか」を特定するためです。

2. なぜ統計情報が「ズレる」のか

PostgreSQLのプランナは、`pg_statistic`にあるヒストグラムを見て「この値は全体の何%くらい含まれているか」を推測します。しかし、現実はそう甘くありません。

  • データ分布の偏り: 特定のIDにデータが集中している場合、単純なサンプリングでは誤差が大きくなります。
  • 相関関係の欠如: カラムAとカラムBが連動している場合(例:「都道府県」と「市区町村」)、プランナはそれぞれ独立していると仮定して計算してしまい、見積もりが大きく外れることがあります。

こういう時、プランナは「あ、これなら全件走査(Seq Scan)したほうが速そうだぞ」と、とんでもない判断を下します。これが「急に遅くなる」の正体です。

3. 実務での調査手順:プランナの脳内を覗く

もしクエリが遅いと感じたら、まずは`pg_statistic`を直接覗いてみましょう。

— 特定のカラムの統計情報を確認
— stakind1は、統計の種類(1は頻出値、2はヒストグラムなど)
SELECT
attname,
stakind1,
stavalues1,
stanullfrac,
stadistinct
FROM pg_statistic s
JOIN pg_attribute a ON a.attrelid = s.starelid AND a.attnum = s.staattnum
WHERE starelid = ‘users’::regclass;

ここで注目してほしいのが `stadistinct` です。ここが実際のデータ数と大きく乖離しているなら、プランナは「重複が少ない」と勘違いして、インデックスを有効に使わない選択をしてしまいます。

—

4. 現場で使える「泥臭い」解決策

統計情報がズレていると分かったら、どう対処すべきか。いきなり「全部`ANALYZE`すればいい」なんて安易なことは言いません。本番環境の巨大なテーブルでそれをやると、逆に負荷が跳ね上がりますからね。

① `ALTER TABLE … SET STATISTICS` で精度を上げる

特定のカラムだけヒストグラムのバケット数を増やしましょう。デフォルトは100ですが、これを最大1000まで増やせます。

— データの偏りが激しいカラムに対して精度を上げる
ALTER TABLE users ALTER COLUMN status_code SET STATISTICS 500;
ANALYZE users;

これだけで、プランナの「視力」が劇的に良くなることがあります。

② 多列統計(Extended Statistics)を使う

これ、意外と知られていないんですが、最強の武器です。「カラムAとBの組み合わせで検索することが多い」なら、これを使わない手はありません。

— 複数のカラム間の相関関係を学習させる
CREATE STATISTICS users_geo_stats (dependencies) ON city_id, prefecture_id FROM users;
ANALYZE users;

これを作っておくと、プランナは「あ、この都道府県ならこの市町村が来るのは必然だな」と理解し、見積もりの精度が跳ね上がります。

—

最後に:データベースと「対話」しよう

データベースのパフォーマンスチューニングは、機械的な設定変更の積み重ねではありません。「プランナがなぜその判断を下したのか」という、データベースの思考プロセスを追いかける「対話」なんです。

`pg_statistic`は、その対話のログであり、設計図です。もしクエリプランナと話が噛み合わないなと思ったら、まずはこのテーブルを覗いてみてください。きっと、プランナが「だって、こんなデータ分布だと思ってたんだもん!」と弁解している声が聞こえてくるはずですよ。

また次回、もっとディープな現場のネタでお会いしましょう。チューニング、楽しんで!

コメント

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