【実務・中級編】 ANALYZEコマンド – PostgreSQL

「あれ、なんか急にクエリが遅くなったぞ?」

そんな経験、一度や二度じゃないはずです。昨日まで爆速だったJOINが、なぜか今日はフルスキャン(全件走査)を始めて、CPUを食いつぶしている。そんな時、一番最初に疑うべきは「統計情報の鮮度」です。

今日はPostgreSQLの隠れた(でも一番重要な)立役者、`ANALYZE`コマンドについて話をしよう。教科書的な説明はドキュメントに任せるとして、現場で「何が起きているのか」「どう付き合うべきか」という話を深掘りしていくよ。

—

なぜ、PostgreSQLは「勘違い」をするのか?

まず、大前提を共有しておこう。PostgreSQLのクエリプランナは、超優秀な参謀だけど、「今のテーブルがどんな状態か」を自分の目では見ていない。

プランナが見ているのは、`pg_statistic`というテーブルに記録された「統計情報」という名のメモ帳だけなんだ。
「このカラムには値が何種類あるか」「NULLはどれくらいあるか」「値の分布はどうなっているか」。このメモ帳が古ければ、プランナは平気で「全件走査したほうが速いよ」なんて的外れなアドバイスをしてくる。

だからこそ、定期的な「情報の更新(=`ANALYZE`)」が必要になるわけだ。

実践:ANALYZEの使い分け

`ANALYZE`には大きく分けて2つの付き合い方がある。

1. 自動実行(Autovacuum)に任せる場合

基本的には、PostgreSQLのバックグラウンドプロセスである`autovacuum`がやってくれる。こいつは「お、このテーブル結構データ更新されたな」と判断したら、自動で`ANALYZE`をかけてくれるんだ。

だから、普通のアプリケーションなら基本的には放置でいい。でも、ここで落とし穴がある。

2. 手動で叩くべき「危ないタイミング」

以下のようなケースでは、`autovacuum`を待たずに、手動で叩くのが現場の鉄則だ。

  • バルクインサートの後: 数百万件のデータを一気に流し込んだ直後。統計情報が古いままだと、プランナは「データはまだ少ない」と勘違いして、インデックスを使わない選択をしがちだ。
  • 大規模なUPDATE/DELETEの後: データの分布がガラッと変わるような操作をした直後。
  • 特定のクエリだけ急激に遅くなった時: 「おかしいな?」と思ったら、迷わず打つ。これが現場の正解だ。

— テーブル全体の統計情報を更新
ANALYZE users;

— 特定のテーブルの、特定のカラムだけを更新(時間がかかるときはこれ)
ANALYZE VERBOSE users (email, created_at);

※ `VERBOSE`をつけると、どのくらいの行をサンプリングしたか等のログが出るから、現場のデバッグには重宝するぞ。

「インデックスはあるのに使われない」の正体

よく後輩から「インデックスを貼ったのにクエリプランが変わらないんです!」と泣きつかれることがある。そんな時、`EXPLAIN`の結果を見ると、案の定「見積もり行数」と「実際の行数」に桁違いの乖離があるんだ。

もし、`ANALYZE`をかけても解決しないなら、それは統計情報の「解像度」の問題かもしれない。

— 特定のカラムの統計情報の解像度を上げる(デフォルトは低め)
ALTER TABLE users ALTER COLUMN status SET STATISTICS 1000;
ANALYZE users;

デフォルトの統計情報保持数(`default_statistics_target`)は通常100なんだけど、値の種類が極端に多いカラム(例えばUUIDや複雑なID)の場合は、これを上げてやることでプランナが「あ、ここには特定の値が偏ってるんだな」と気づいてくれるようになる。

最後に:先輩からのアドバイス

`ANALYZE`は、いわば「視力の矯正」だ。眼鏡をかけないと、プランナはぼやけた視界の中で「なんとなくこっちが速そう」と適当にルートを決めることになる。

  • 「遅いな」と思ったら、まずは`ANALYZE`を疑う。
  • 大量のデータ投入後は、習慣的に`ANALYZE`する。
  • それでもダメなら`STATISTICS`の値を調整する。

この3つを頭に入れておくだけで、現場でのトラブルシュートのスピードは劇的に変わるはずだ。

データベースをチューニングするのは、エンジンを調整するようなもの。理屈を知れば、PostgreSQLは最高のパフォーマンスで応えてくれる。ぜひ、明日からの運用で意識してみてくれ!

コメント

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