「なぜPostgreSQLはそこまで見当違いなプランを選ぶのか?」を解決する:拡張統計情報の奥義
PostgreSQLのクエリプランナは、世界で最も賢いアルゴリズムの一つですが、時折「どうしてその見積もりになった?」と頭を抱えたくなるようなプランを吐き出すことがあります。
特に、`WHERE` 句で複数の列に条件を指定したとき、プランナが「行数は100万件」と予測したのに、実際はたったの「10件」しか返ってこなかった……そんな経験、DBAなら一度はありますよね。この見積もりの乖離こそが、Nested LoopがHash Joinに化けたり、インデックスを無視してフルスキャンが走ったりする諸悪の根源です。
今日は、そんな見積もりの「迷走」を根本から正すための切り札、「拡張統計情報(Extended Statistics)」について深掘りしていきましょう。
—
プランナの「独立性の仮定」という罠
まず、なぜ見積もりが狂うのか。その根本的な理由は、PostgreSQLの統計情報がデフォルトでは「列ごとの独立性」を前提としているからです。
例えば、`city`(都市)と `zip_code`(郵便番号)という列を持つテーブルがあるとします。人間から見れば、「都市が決まれば郵便番号の範囲も自ずと決まる(強い相関がある)」ことは明白です。しかし、プランナはこれらを別々の統計情報として扱います。
そのため、以下のクエリを実行すると:
SELECT FROM addresses WHERE city = ‘Tokyo’ AND zip_code = ‘100-0001’;
プランナは、「Tokyoの出現確率(例えば1/100)」と「その郵便番号の出現確率(例えば1/10000)」を掛け算してしまいます。結果として「1/1,000,000」という過小評価を行い、間違った結合戦略を選択するわけです。
拡張統計情報の真骨頂:CREATE STATISTICS
この「相関関係の欠如」を補うのが `CREATE STATISTICS` です。
単に「統計を集める」だけでなく、どのような種類の相関を追跡させるかを選択できるのがPostgreSQLの面白いところです。
1. 依存関係(dependencies)
`dependencies` は、列間の関数的な依存関係を追跡します。先ほどの都市と郵便番号の例であれば、これが最適です。これにより、プランナは「都市と郵便番号の両方を指定しても、確率は単独の都市の出現率とほぼ変わらない」という事実を理解できるようになります。
2. 多変量N個の個別値(ndistinct)
`ndistinct` は、複数の列を組み合わせた値の「ユニーク数」を正確に把握します。`GROUP BY col_a, col_b` を頻繁に行うクエリにおいて、ハッシュテーブルのサイズを見誤ってディスクスピル(Disk Spill)が発生するのを防ぐのに絶大な効果を発揮します。
3. MCVリスト(most_common_vals)
これが最強の武器です。特定の列の組み合わせにおいて、頻出する値のパターンをヒストグラム的に保持します。単なる確率の掛け算ではなく、「この組み合わせが来たら実際はこれくらいの行数だ」という実測値に近い見積もりが可能になります。
—
トラブルシューティング:どこで使うべきか?
「じゃあ、すべてのテーブルに拡張統計をかければいいのか?」と言えば、それは違います。
- ANALYZEのコスト: 拡張統計を作成すると、`ANALYZE` 実行時のオーバーヘッドが増加します。数千万行のテーブルで列の組み合わせを乱立させると、メンテナンスウィンドウの時間を圧迫します。
- 観測の必要性: まずは `EXPLAIN ANALYZE` を実行し、`actual rows` と `estimated rows` の乖離が激しいクエリを見つけるのが先決です。乖離がある箇所にのみ、ピンポイントで投入する。これが職人の仕事です。
内部アーキテクチャの視点
拡張統計は `pg_statistic_ext` システムカタログに保存されます。プランナはクエリ最適化のフェーズで、`WHERE` 句の条件が拡張統計の定義とマッチするかをチェックし、マッチすれば「独立性の仮定」を捨てて、この統計情報を優先的に利用します。
もし、設定したのにプランが変わらない場合は、`pg_stats_ext` ビューを確認してみてください。統計が正しく収集されているか、`last_updated` は最新か。ここを確認するだけで、解決の糸口が見えることがほとんどです。
—
最後に:統計情報は「生き物」である
拡張統計情報を導入することは、単なる設定作業ではありません。それはデータベースという「生き物」に対して、人間が持っているドメイン知識(この列とあの列は連動しているんだよ、という事実)を教え込む作業です。
「なぜかこのクエリだけ遅い」という不満を「技術的な洞察」に変えるために、ぜひ `CREATE STATISTICS` を活用してみてください。プランナが本来の輝きを取り戻した瞬間、クエリの実行計画が美しく整列する様子を見るのは、エンジニアにとって最高の快感ですよ。
それでは、また次回の深掘りでお会いしましょう。Happy Hacking!
コメント