【実務・中級編】 拡張統計情報(CREATE STATISTICS) – PostgreSQL

「ねえ、またあのクエリでハマってるの?」

PostgreSQLを触っていると、たまに不思議な現象に遭遇しないかな。インデックスもちゃんと貼ってあるし、`EXPLAIN ANALYZE`を見てもコスト計算は低いはずなのに、なぜか実行計画がめちゃくちゃなものになっている。ネストループで数十万件も回そうとしていたり、本来なら一瞬で終わるはずのクエリが数秒かかっていたり……。

そんな時、たいていの原因は「プランナが統計情報を信じすぎて、逆に騙されている」ことにあるんだ。

今日は、そんな泥沼から君を救い出すための切り札、「拡張統計情報(`CREATE STATISTICS`)」について話そうと思う。これを知っているかいないかで、DBエンジニアとしての引き出しの深さがガラッと変わるよ。

—

なぜ「普通の統計情報」だけじゃダメなのか?

PostgreSQLのプランナは、テーブルの列ごとに統計情報を取っている。「この列にはこういうデータがこれくらい入っている」っていう情報を元に、WHERE句の絞り込み率(選択率)を計算するんだ。

でもね、現実はそんなに単純じゃない。

例えば、`users`テーブルに「都道府県(prefecture)」と「市町村(city)」という列があったとする。「東京都」の行は全体の10%で、「新宿区」の行も全体の1%だとしよう。

ここで、`WHERE prefecture = ‘東京都’ AND city = ‘新宿区’` というクエリを投げると、プランナはどう計算するか。
「10% × 1% = 0.1%」と単純に乗算してしまうんだ。

でも、実際はどう?「新宿区」は「東京都」にしかないんだから、この確率は1%と変わらないはずだよね。プランナは「列間に相関がある」ということを知らないから、勝手に独立事象として計算して、過小評価(過剰な見積もり)をしてしまうんだ。

結果、プランナは「これならインデックス使わずに全件スキャンしたほうが早いな」と判断してしまい、悲劇が始まる。

—

救世主:拡張統計情報(CREATE STATISTICS)

PostgreSQL 10で導入されたこの機能は、まさにその「相関関係」をプランナに教えてあげるためのものだ。

使い方は驚くほどシンプル。

CREATE STATISTICS stats_pref_city (dependencies)
ON prefecture, city FROM users;

これだけで、PostgreSQLは「この2つの列には依存関係がある」という統計情報を別途作成してくれる。これを作った後に `ANALYZE` を実行すれば、プランナは「あ、この2つは相関してるから、見積もりを補正しなきゃ」と賢くなってくれるんだ。

具体的な使用例:多機能な統計情報の種類

`CREATE STATISTICS` にはいくつか種類があるけれど、実務でよく使うのはこの2つだ。

1. `dependencies`(依存関係): さっきの例のように、列同士の「包含関係」や「相関」を教える。
2. `ndistinct`(個別値の数): `GROUP BY` を重ねた時の行数を推定する。複数の列を組み合わせたユニークな値の数が、別々に見た時とどう違うか。

例えば、ログテーブルを `app_id` と `event_type` でグループ化するクエリが遅いなら、こうやって教えることができる。

CREATE STATISTICS stats_app_event_dist (ndistinct)
ON app_id, event_type FROM logs;

—

実践での注意点:魔法じゃない、道具だよ

ここが一番大事なところなんだけど、「なんでもかんでも統計情報を作ればいい」というわけじゃないんだ。

  • オーバーヘッド: 統計情報の数が増えれば、`ANALYZE` の時間が延びるし、カタログの管理コストも上がる。本当に遅いクエリ、あるいは「ここがボトルネックになっている」と確信がある場所に絞って作るのがプロのやり方だ。
  • デバッグの鉄則: まずは `EXPLAIN ANALYZE` を見て、「推定行数(estimated)」と「実測行数(actual)」が大きく乖離していないかを確認すること。乖離しているなら、そこに統計情報の出番があるかもしれない。
  • 削除も忘れずに: 一度作ったら一生モノじゃない。テーブルのスキーマやデータの傾向が変われば、不要な統計情報が逆に害になることもある。不要になったら `DROP STATISTICS` で綺麗に掃除しよう。

—

最後に:データベースとの「対話」を楽しもう

PostgreSQLをチューニングしていると、時々DBと会話しているような気分になることがある。「お前、ここを独立している列だと思ってるだろ? 違うんだよ、ここはセットで動くデータなんだよ」と教えてあげる。

`CREATE STATISTICS` は、その対話を深めるための最高にクールなツールだ。

もし今度、実行計画が納得いかない動きをしていたら、まずは落ち着いて「列間に相関はないか?」と疑ってみてほしい。教科書通りのSQLを書くだけじゃなく、データの性質を理解してDBに伝えてあげる。それが、君を「SQLを書く人」から「データベースを操るエンジニア」に変えてくれるはずだよ。

また何か詰まったら、いつでも聞きに来て。一緒に解決しよう。

コメント

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