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

「なぜかクエリが遅い」を解決する第一歩。PostgreSQLのANALYZEと上手く付き合う方法

現場で「最近、特定のSELECTクエリが急に重くなったんだよね」なんて相談を受けると、僕がまず確認するのは実行計画(EXPLAIN)と、そしてこの「統計情報の鮮度」です。

PostgreSQLにおける `ANALYZE` は、いわばオプティマイザ(クエリの司令塔)に対する「最新の地図」を渡す作業です。これが古いと、司令塔はとんでもない遠回りルートを選んでしまい、本番環境で悲劇が起きる。

今日は、そんな `ANALYZE` の仕組みと、現場でハマりやすい罠について、少し深掘りして話してみようと思います。

—

1. ANALYZEは「全件走査」ではない

まず、誤解している人がたまにいるんだけど、`ANALYZE` はテーブルを全件スキャンするわけではありません。そんなことをしたら、巨大なテーブルではDBが止まってしまいますよね。

`ANALYZE` は、設定されたパラメータに基づいてテーブルの一部をサンプリングし、データの分布(ヒストグラムや頻出値)を推定して、`pg_statistic` というシステムカタログに書き込みます。

この「地図」をもとに、PostgreSQLは「この条件ならインデックスを使うよりフルスキャンした方が早そうだな」といった賢い判断を下しているわけです。

—

2. 自動ANALYZE(Autovacuum)との付き合い方

普段、手動で `ANALYZE` を叩くことはあまりないはずです。通常は `autovacuum` プロセスが裏で勝手にやってくれていますからね。でも、ここが曲者なんです。

自動実行のトリガー条件は、ざっくり言うとこれです。

> 変更された行数 > (scale_factor × テーブルの全行数) + threshold

デフォルト設定だと、だいたい「テーブルの10% + 50行」が更新・挿入・削除されると発動します。

実務での落とし穴

例えば、1億行ある巨大なテーブルを想像してみてください。10%って1,000万行ですよ。これだけデータが変わるまで統計情報が更新されないと、オプティマイザは数ヶ月前の古いデータをもとにプランを立て続けることになります。

そんなときは、そのテーブルだけ個別に設定をいじるのが鉄則です。

— 特定のテーブルだけ、もう少し敏感にANALYZEを走らせる設定
ALTER TABLE orders SET (
autovacuum_analyze_scale_factor = 0.01, — 1%の変更で発動
autovacuum_analyze_threshold = 1000 — 最小しきい値
);

こうすることで、巨大なテーブルでも統計情報の鮮度を保ちやすくなります。

—

3. 手動ANALYZEが必要になる「その時」

基本は自動にお任せでいいんですが、僕たちが手動で `ANALYZE` を叩くべきタイミングは確実にあります。

1. バッチ処理で大量データを投入した後

  • 大きな `INSERT` や `COPY` を流した直後は、統計情報がまだ古いままです。バッチ処理の最後に忘れずに入れておきましょう。

2. 特定のクエリプランが明らかに不自然な時

  • `EXPLAIN ANALYZE` を実行して、実際の行数と推定行数(rows)に大きな乖離がある場合。これが起きていたら、迷わず `ANALYZE テーブル名;` です。

注意点:ロックについて

`ANALYZE` はテーブルに共有ロックをかけますが、通常のSELECTやDML(INSERT/UPDATE/DELETE)をブロックすることはありません。だから「本番環境で叩くのが怖い」と過度に心配する必要はありません。ただし、CPU負荷はそれなりにかかるので、リソースに余裕がある時間帯にやるのが大人のマナーですね。

—

先輩からのアドバイス:情報の「解像度」を上げる

最後にちょっとした裏技を。`ANALYZE` が収集する統計情報の精度は、実はカラムごとに変更できます。

「このカラムは値の種類がめちゃくちゃ多いから、デフォルトのサンプリングじゃ精度が足りないな」と感じたら、こうやって個別指定してあげてください。

— このカラムだけ、ヒストグラムのバケット数を増やして精度アップ
ALTER TABLE users ALTER COLUMN email SET STATISTICS 500;

デフォルトは100ですが、これを増やすと `ANALYZE` の負荷は少し増える代わりに、複雑なWHERE句に対する推定精度が劇的に向上します。

—

まとめ

`ANALYZE` は、データベースという「生き物」を健康に保つためのメンテナンスです。
「なんか遅いな」と感じたとき、真っ先に `pg_stat_user_tables` を覗いて、いつ `last_analyze` が実行されたのかを確認する。そんな癖がつくと、DBエンジニアとしてのレベルは一段階上がります。

もし皆さんの現場で、「なぜかインデックスが使われない」「プランが極端に遅い」という現象があれば、まずは統計情報を疑ってみてください。きっと、解決の糸口が見つかるはずですよ。

それでは、また現場で!

コメント

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