「え、なんで全件スキャン?」と悩んだら。PostgreSQLの「関数従属性統計」でオプティマイザを賢くする方法
現場で働いていると、たまに「どう見ても高速に終わるはずのクエリが、なぜかフルスキャンして爆死している」なんて場面に遭遇しませんか?
「インデックスは貼ってあるし、`ANALYZE`も回した。統計情報も最新のはず。なのに、なぜPostgreSQLはこんなヘンテコな実行計画を立てるんだ……!」
そんな時、たいていの原因は「列同士の相関関係」をオプティマイザが理解できていないことにあります。今日は、そんな悩みを一発で解決してくれる、PostgreSQLの隠れた武器「関数従属性統計(Functional Dependency)」について、実務的な話をしようと思います。
—
なぜオプティマイザは「勘違い」をするのか
まず、PostgreSQLのオプティマイザの基本ルールを知っておきましょう。彼は基本的に「各条件は独立している」という前提で計算をします。
例えば、こんなテーブルがあるとします。
- `city`(都市名:東京、大阪、福岡…)
- `zip_code`(郵便番号)
この2つの列には、「ある郵便番号が決まれば、必然的に都市も決まる」という関係がありますよね。これを専門用語で「関数従属性」と呼びます。
ここで、以下のクエリを投げたとします。
SELECT FROM addresses
WHERE city = ‘福岡市’ AND zip_code = ‘810-0001’;
オプティマイザはこう考えます。
1. 「`city = ‘福岡市’`である確率は10%くらいかな」
2. 「`zip_code = ‘810-0001’`である確率は0.01%くらいだな」
3. 「じゃあ、両方を満たす確率は `0.1 0.0001 = 0.00001` だ!」
……でも、実際には`zip_code`がその値なら、`city`は必ず福岡市です。確率は`0.0001`のままなのに、オプティマイザは過小評価して「このクエリはほとんどヒットしないはずだ!」と判断し、インデックスではなく無謀な全件スキャンを選択してしまうことがあるんです。
—
「関数従属性統計」という処方箋
これを解決するのが、PostgreSQL 10から導入された「拡張統計(Extended Statistics)」の一部である、関数従属性統計です。
これはデータベースに対して、「この列とこの列には強い結びつきがあるから、確率を計算するときはセットで考えてね!」と教えてあげる機能です。
実際の使い方
やり方は拍子抜けするほど簡単です。以下のコマンドを打つだけ。
CREATE STATISTICS stats_city_zip (dependencies)
ON city, zip_code FROM addresses;
これだけで、PostgreSQLは「`zip_code`が決まれば`city`も決まる」という相関関係を統計情報として学習し始めます。
あとは、いつものように `ANALYZE` を実行するだけです。
ANALYZE addresses;
—
どんな時に効果を発揮するのか?
実務でこの機能を活用すべきなのは、以下のようなケースです。
- 住所や地域コード: `都道府県`と`市区町村`、`郵便番号`など。
- カテゴリーとサブカテゴリー: `親カテゴリID`と`子カテゴリID`。
- 製品コードと型番: `ブランド名`と`モデル番号`。
逆に言えば、「片方の値が決まれば、もう片方の値が一意(または極めて高い確率)で決まる」ような列の組み合わせには、迷わず適用して良いでしょう。
—
注意点:魔法の杖ではない
もちろん、何でもかんでも統計を作ればいいというわけではありません。
1. 書き込み負荷: 統計オブジェクトが増えると、`ANALYZE`のコストがわずかに上がります。頻繁に更新されるテーブルで、何百もの統計を作ったりするのは避けるべきです。
2. まずは実行計画を確認: `EXPLAIN ANALYZE` を見て、「推定行数(rows)」と「実際の行数(actual rows)」に大きな乖離があるか確認してください。乖離がなければ、そのクエリに拡張統計は不要です。
—
まとめ:データベースと「対話」しよう
PostgreSQLのオプティマイザは非常に優秀ですが、あくまで「統計情報」という限られた視界の中で判断しています。
「なぜこいつはこんな非効率な道を選ぶんだ?」とイライラするのではなく、「ああ、こいつはまだこの列同士の深い関係を知らないんだな」と気づいてあげてください。そして、`CREATE STATISTICS` という言葉で、ちょっとだけヒントを教えてあげる。
そうやってデータベースと「対話」できるようになると、チューニングは一気に楽しくなりますよ。
今日の現場での作業、ぜひ試してみてください。劇的にクエリが速くなる瞬間は、エンジニアとして一番気持ちいい瞬間ですから。
それでは、また!
コメント