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

「なぜプランナは間違えるのか?」その答えは pg_statistic にある

現場で働いていると、たまにこんな悲鳴を聞く。「さっきまで爆速だったクエリが、急に遅くなった!」と。

DBエンジニアとして経験を積んでくると、こういうトラブルの多くが「実行計画(EXPLAIN)の迷走」に起因していることが直感的にわかるようになる。そして、その迷走の根源を辿っていくと、必ずといっていいほど「pg_statistic」という、PostgreSQLの頭脳とも言えるシステムカタログに行き着くんだ。

今日は、教科書にはあまり書いていない「pg_statistic との付き合い方」について、少し掘り下げて話してみようと思う。

—

pg_statistic は「クエリプランナの地図」だ

PostgreSQLのクエリプランナは、賢いAIのようなものだけど、彼らは「勘」で動いているわけじゃない。彼らが唯一頼りにしている「地図」が `pg_statistic` なんだ。

`ANALYZE` コマンドを実行したとき、PostgreSQLはテーブルのデータをサンプリングして、「この列にはどんな値がどれくらいあるのか?」「Nullはどれくらいあるのか?」といった統計情報をこのカタログに書き込む。

もしこの統計情報が古かったり、実態と乖離していたりすれば、プランナは「テーブルの行数が少ないはずだからインデックスは使わずに全件走査(Seq Scan)しよう」なんていう、とんでもない判断を下す。これが、いわゆる「クエリの遅延」の正体だ。

まずは「生の状態」を覗いてみよう

`pg_statistic` は直接参照することもできるけど、実は人間には非常に読みづらい形式で保存されている。というのも、統計情報は「最も頻出する値(MCV)」や「ヒストグラム」など、計算効率を最優先したバイナリに近いデータ構造になっているからだ。

直接覗くなら、こんなSQLを叩いてみるといい。

— 特定のテーブルの統計情報を見てみる
SELECT
stxname,
stxkind
FROM pg_statistic_ext
WHERE stxrelid = ‘target_table’::regclass;

ただ、実際の実務では `pg_statistic` を直接こねくり回すより、まずは `pg_stats` ビューを見るのが定石だ。こっちは人間が読みやすいように整形されているからね。

— 頻出値(Most Common Values)をチェックする
SELECT
column_name,
most_common_vals,
most_common_freqs
FROM pg_stats
WHERE tablename = ‘orders’ AND column_name = ‘status’;

ここで `most_common_vals`(よく出てくる値)と `most_common_freqs`(その出現確率)を見て、「ああ、完了ステータスのデータが9割を超えているな。だからプランナはこの列のインデックスを無視したんだな」と納得できるようになったら、君も一人前のDBエンジニアだ。

「統計情報が足りない」という罠

最近のPostgreSQLは優秀だから、基本的には `autovacuum` が勝手に `ANALYZE` を走らせてくれる。でも、実務では以下のようなケースで統計情報が「嘘つき」になることがある。

1. データ分布が極端に偏ったとき:
特定のIDだけが異常に多い、といったケースではデフォルトのヒストグラムだけでは精度が足りないことがある。
2. 相関のある列でクエリを投げるとき:
「都道府県」と「市区町村」のように、列同士に相関がある場合、プランナは「それぞれ独立している」と仮定して計算し、見積もりを大きく外すことがある。

そんな時は、拡張統計(Extended Statistics)の出番だ。

— 相関関係を教え込む(PostgreSQL 10以降)
CREATE STATISTICS stats_pref_city
ON prefecture, city FROM orders;

— これでプランナは「都道府県と市区町村はセットで考えるべき」と理解する

先輩からのアドバイス:怖がらずに「手動ANALYZE」を

新人さんは「統計情報をいじると壊れるんじゃないか」と怖がることがあるけれど、統計情報を更新するだけなら何も壊れない。むしろ、データをごっそり入れ替えた直後や、夜間バッチで大量のレコードを更新した直後は、待機せずに手動で `ANALYZE` を叩くのがプロの流儀だ。

— 大量更新の直後に実行して、プランナを最新の状態にする
ANALYZE VERBOSE orders;

もしそれでもプランナが迷走するなら、`ALTER TABLE … SET STATISTICS` で統計情報の粒度(サンプリング数)を上げてやるのも一つの手だ。

—

まとめ

`pg_statistic` は、PostgreSQLの「経験則」が詰まった宝箱だ。
クエリが遅いとき、すぐにSQLを書き換えるのではなく、「プランナは何を勘違いしているのか?」という視点で `pg_stats` を覗いてみてほしい。

「なぜ?」を突き詰めるプロセスこそが、君をただのコーダーから、本物のDBエンジニアへと成長させてくれるはずだ。

また何か壁にぶつかったら、いつでも聞きに来てくれ。データベースの深淵を一緒に覗こうじゃないか。

コメント

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