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

なぜPostgreSQLのプランナは「嘘」をつくのか?:拡張統計情報(CREATE STATISTICS)の活用術

現場でバリバリとクエリを書いていると、たまに「いや、どう考えてもこのクエリは一瞬で終わるはずなのに、なんでこんなに時間がかかるんだ?」と頭を抱える瞬間、ありますよね。

実行計画(`EXPLAIN ANALYZE`)を見てみると、プランナが「ここは数行しか返ってこないはずだから、Nested Loopでいこう!」と判断しているのに、実際には数万行が返ってきてHash Joinに切り替わった結果、システム全体が悲鳴を上げている……なんていう悲劇。

これ、実はPostgreSQLが「列同士の相関関係」を理解できていないことが原因かもしれません。今日は、そんな「プランナの勘違い」を正し、パフォーマンスを劇的に改善する『拡張統計情報(CREATE STATISTICS)』について、現場の知見を共有したいと思います。

—

なぜプランナは読みを外すのか

PostgreSQLの標準的な統計情報は、基本的に「各列の単独の分布」を見ています。

例えば、`users`テーブルに `prefecture`(都道府県)と `city`(市区町村)という2つの列があるとしましょう。「東京都」という値の出現頻度と、「新宿区」という値の出現頻度は個別に把握できています。

しかし、プランナは「東京都を選択したとき、新宿区が選ばれる確率は極めて高い(相関がある)」という関係性までは知りません。

そのため、PostgreSQLは単純に確率を掛け算してしまいます。
「都道府県が東京都である確率(仮に10%) × 市区町村が新宿区である確率(仮に1%) = 0.1%」
……と見積もるわけです。実際には30%くらいあるかもしれないのに、これではプランナは「あ、この条件なら数行しか返ってこないな!」と楽観的な計画を立ててしまいます。これが「見積もりの乖離」の正体です。

救世主:CREATE STATISTICSの出番

この「勘違い」を正すのが `CREATE STATISTICS` です。こいつを使うと、特定の列の組み合わせについて「ここの列たちはセットで考えると、こういう分布になっているよ」という情報をプランナに教え込むことができます。

1. 関数依存関係(Functional Dependencies)

「ある列が決まれば、別の列の値も自動的に決まる」という関係(例:郵便番号が決まれば、都道府県も決まる)がある場合に有効です。

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

これを作成したあと、`ANALYZE` を実行すると、プランナは「あ、この2つはセットで見ないといけないのか」と理解し、見積もりの精度が劇的に向上します。

2. 多変量N個体数(NDistinct)

「2つの列を組み合わせたとき、ユニークな値が何通りあるか」を推定します。これは、`GROUP BY` を複数列で行う場合や、`DISTINCT` を組み合わせるクエリで威力を発揮します。

CREATE STATISTICS stats_user_groups
(ndistinct)
ON prefecture, city FROM users;

これがあるだけで、グループ化のコスト見積もりが正確になり、適切なメモリ割り当てが行われるようになります。

—

実務で使う際の「心得」

「じゃあ、全部の列に統計情報を貼れば最強じゃん!」と思うかもしれませんが、それは罠です。

  • オーバーヘッドに注意: `CREATE STATISTICS` を作成すると、その分 `ANALYZE` の負荷が増えます。テーブルが巨大で更新頻度が高い場合、統計情報の更新がボトルネックになることもあります。
  • 本当に困っているところにだけ使う: 実行計画を見て、明らかに「見積もり行数」と「実際行数」が桁違いにズレているクエリを見つけてください。そのボトルネックに対してピンポイントで適用するのが、プロの仕事です。
  • ANALYZEを忘れずに: 統計情報を作っただけでは反映されません。必ず `ANALYZE テーブル名;` を実行して、データを再スキャンさせてください。

最後に

データベースエンジニアの仕事は、SQLを書くだけではありません。PostgreSQLという「賢いけれど、時々空回りする部下」に対して、いかに正確な判断材料を与えて、気持ちよく働いてもらうか。そのための調律こそが、チューニングの醍醐味です。

もし今度、不可解な実行計画に出くわしたら、ぜひ `CREATE STATISTICS` を思い出してください。きっと、あなたのクエリを救ってくれるはずです。

それでは、良いチューニングライフを!

コメント

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