【テクニカル・上級編】 ANALYZEコマンド – PostgreSQL

統計情報の「鮮度」は、エンジニアの矜持。PostgreSQLのANALYZEと向き合う夜

データベースエンジニアとして長く現場に立っていると、ふと「なぜこのクエリは突然、劇的に遅くなったのか?」という問いに直面することがあります。

インデックスは貼ってある。実行計画も確認した。なのになぜ、プランナはあえてフルスキャンを選んだのか? 多くのケースで、その犯人は統計情報の乖離――つまり、`ANALYZE`が捉えきれていない「データの現実」にあります。

今日は、PostgreSQLの統計情報収集コマンドである`ANALYZE`について、教科書には載っていない「現場の深淵」を少し覗いてみようと思います。

—

なぜ、プランナは「嘘」をつくのか

PostgreSQLのクエリプランナは、いわゆる「コストベース(Cost-Based Optimizer)」です。彼らは神ではない。彼らが意思決定を下すための唯一の拠り所が、`pg_statistic`(あるいはシステムビューの`pg_stats`)に格納された統計情報です。

`ANALYZE`がテーブルをスキャンし、各カラムの分布や不一致値(n_distinct)、NULLの割合、そして最頻値(MCV: Most Common Values)をカタログに書き込む。プランナはそれを元に「この条件なら、何行ヒットするか?」を予測し、コストを計算します。

ここで重要なのは、「ANALYZEはサンプリングである」という事実です。

デフォルトの`default_statistics_target`(通常100)は、各カラムから100個のバケット(ビン)をサンプリングしてヒストグラムを作ります。しかし、データが極端に偏っていたり、時間経過とともに分布が激変していたりすると、このサンプリング精度ではプランナをミスリードさせることになります。

パフォーマンストラブルの「よくある現場」

私が過去に遭遇したトラブルで最も印象深いのは、ある大規模な決済履歴テーブルでの事例でした。

  • 現象: 特定の期間のデータだけ、クエリが100倍遅くなる。
  • 原因: データの挿入パターンに偏りがあり、最新のデータが「例外的な分布」をしていた。
  • 結末: `autovacuum`が起動するまでのラグの間、古い統計情報が「最新のデータは存在しない」とプランナに誤認させていた。

ここで「とりあえず`ANALYZE`を手動で叩いて解決」とするのは簡単です。しかし、真のエンジニアなら、なぜそれが起きているのかを考えるべきです。

もし統計情報の鮮度が原因なら、`ALTER TABLE … SET STATISTICS`で対象カラムのサンプリング精度を上げるか、あるいは`pg_stats_ext`を使った「拡張統計情報(Extended Statistics)」を検討すべきです。特に、カラム間に強い相関がある場合(例:郵便番号と住所)、単一カラムの統計情報だけではプランナは一生、正確な行数を見積もれません。

現場で役立つ「ANALYZE」の運用Tips

私が日々の業務で意識している、いくつかのアドバイスを共有します。

  • autovacuumに頼りすぎない

高頻度で更新されるワークロードにおいて、autovacuumのデフォルト設定は往々にして「遅すぎる」ことがあります。特に`autovacuum_analyze_scale_factor`は、テーブルが巨大化するほど悪影響を及ぼします。テーブルの性格に応じて、個別にチューニングする勇気を持ってください。

  • 特定のクエリには「手動」の介入を恐れない

統計情報が自動更新されるのを待てないほどクリティカルなバッチ処理があるなら、スクリプトの最後で`ANALYZE table_name`を明示的に実行するのは、決して「泥臭い対処」ではありません。それは「データの状態をクエリに同期させる」という極めて理にかなった制御です。

  • 統計情報の「精度」と「コスト」のトレードオフ

`statistics_target`を最大(10000)にすればプランナは賢くなりますが、その分`ANALYZE`の実行コストは増大し、CPUを消費します。どこまで精度を高めるかは、そのテーブルの「クエリの重さ」と「データの更新頻度」のバランスで決めるべきです。

最後に:データベースと対話するということ

データベースは、私たちが命令を書き込むだけの箱ではありません。データそのものが生き物のように変化し、それに応じてプランナの判断も揺れ動く。その「変化」を観測し、適切なタイミングで「真実(統計情報)」を教えてあげること。それが`ANALYZE`というコマンドの本質です。

もし今、あなたのデータベースで不可解な遅延が起きているなら、まずは`pg_stats`を覗いてみてください。そこに書かれている「見積もり」と「実際の行数」にどれほどの乖離があるか。

その差こそが、あなたがエンジニアとして解決すべき、もっとも面白いパズルなのかもしれません。

それでは、良いクエリチューニングライフを。

コメント

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