こんにちは!データベースエンジニアとして日々PostgreSQLと格闘している私ですが、今日は少しマニアックだけど、知っていると「おっ、やるな」と思われる「N-Distinct(エヌ・ディスティンクト)」というお話をしてみたいと思います。
「統計」とか「見積もり」なんて聞くと、なんだか難しそうですよね。でも、実はこれ、私たちの日常生活にある「あるある」と同じなんです。
—
そもそも、PostgreSQLは何を見て判断しているの?
PostgreSQLがクエリ(命令文)を実行するとき、実は裏で「このやり方でいいかな?こっちのほうが速いかな?」と一生懸命シミュレーションしています。
そのとき、PostgreSQLが一番頼りにしているのが「統計情報」という名のメモ帳です。例えば、「このテーブルには全部で1万行あるよ」「『都道府県』という列には47種類の値があるよ」といったデータが書かれています。
これがあるおかげで、PostgreSQLは「あ、この条件ならサクッと検索できそうだな!」と判断できるわけです。
「組み合わせ」になると、急に迷子になる
さて、ここからが本題です。例えば、こんなデータがあると想像してみてください。
- 都道府県(東京、大阪、福岡……など47種類)
- 市区町村(たくさんありますね)
ここで、「東京都の世田谷区」という条件で検索をかけたとします。
PostgreSQLは、「都道府県」の統計と「市区町村」の統計を別々に見て、「まあ、このくらいの行数かな?」と見積もります。
でも、ここで問題が発生します。「都道府県」と「市区町村」という2つの情報を組み合わせたとき、PostgreSQLは少し混乱してしまうんです。
「東京都の世田谷区」は1つしかないけど、PostgreSQLは「東京都も世田谷区も、それぞれバラバラに値がたくさんあるから、掛け合わせたら結構な行数になるんじゃない?」と、とんでもなく多い数字を予想してしまうことがあるんです。
これが「見積もりのミス」です。見積もりが外れると、PostgreSQLは「よし、一番時間がかかる方法で検索しよう!」なんていう的外れな選択をしてしまい、クエリが激重になる……なんてことが起こります。
「N-Distinct」という解決策
そこで登場するのが「N-Distinct(複数列統計情報)」です。
これは簡単に言うと、PostgreSQLに対して「ねえ、都道府県と市区町村をセットで見ると、ユニークな組み合わせはこれくらいあるから覚えておいてね!」と教えてあげる機能です。
料理に例えるなら……。
「カレー」という単語と「ライス」という単語を別々に考えるのではなく、「カレーライス」というセットメニューとしてメニュー表に載せておくイメージです。これなら、「カレー」と「ライス」を別々に頼む人より、ずっと正確に行数が予想できますよね。
どうやって設定するの?
PostgreSQLでこれを設定するのは驚くほど簡単です。以下のコマンドを実行するだけ。
CREATE STATISTICS 統計名 (ndistinct) ON 都道府県, 市区町村 FROM テーブル名;
これだけで、PostgreSQLは「なるほど、この2つの列を組み合わせると、これくらいのユニークな組み合わせがあるんだな!」と学習してくれます。
あとは、いつものように `ANALYZE` コマンドを実行しておけば、統計情報が最新の状態に更新されます。これでもう、見積もりのせいでクエリが遅くなるという悲劇とはおさらばです!
—
まとめ:データベースと仲良くなるために
データベースは、私たちが思っているよりもずっと素直です。私たちが正しい情報(統計情報)を教えてあげれば、それだけ期待に応えて、最高のパフォーマンスで動いてくれます。
もし皆さんのシステムで「なぜか特定の検索だけめちゃくちゃ遅いんだよな……」という悩みがあれば、この「N-Distinct」を思い出してみてください。
「もしかして、列の組み合わせが上手く伝わっていないのかな?」と考えてみるだけで、チューニングの腕前はグッと上がります。ぜひ、次の開発で試してみてくださいね!
それでは、また次回のブログでお会いしましょう。ハッピー・クエリライフを!
コメント