【実務・中級編】 カラム単位の統計情報設定 – PostgreSQL

「クエリがなぜか遅い」。現場でそんな相談を受けたとき、真っ先に疑うのはインデックスの欠如ですが、次に疑うべきは「オプティマイザが間違った道を選んでいる」という事実です。

PostgreSQLのオプティマイザは、統計情報をもとに「どのルートが一番速いか」を判断します。でも、データに偏りがある場合、デフォルトの統計情報(`default_statistics_target`)では精度が足りず、プランナが「フルスキャンの方が速いだろう」と勘違いしてしまうことがよくあるんです。

今日は、そんな「勘違い」を矯正する切り札、`ALTER TABLE … ALTER COLUMN … SET STATISTICS` について、現場の経験を交えて話そうと思います。

—

なぜ統計情報の精度が重要なのか?

PostgreSQLは、テーブルの各カラムに対してヒストグラム(データの分布図)を保持しています。デフォルトでは100個のバケットを使って分布を記録しますが、これだと数百万行あるテーブルで、非常に特殊な値(特定のフラグだけ極端に多いなど)を追いきれないことがあります。

するとどうなるか。プランナは「この値は全体の1%くらいかな」と見積もるのに、実際は30%も含まれていたりする。この見積もりのズレが、Nested Loopを無理やり選ばせたり、インデックスを無視させたりする「クエリ遅延の元凶」になるわけです。

具体的にどうやって設定するのか

使い方はシンプルです。特定のカラムの統計精度を上げたい場合、以下のようにコマンドを打ちます。

— 統計情報の精度をデフォルトの100から、最大値の1000まで引き上げる
ALTER TABLE orders ALTER COLUMN status SET STATISTICS 1000;

— 反映させるために統計情報を再収集する
ANALYZE orders;

これだけで、そのカラムに対するヒストグラムの解像度が10倍になります。プランナは、値の出現頻度をより正確に把握できるようになり、より適した実行計画を選択してくれるようになります。

どんなときに使うべき?(現場の判断基準)

この設定は「とりあえず全部上げとけ」というものではありません。統計情報を読み込むコストもわずかながら増えますし、なにより管理が煩雑になります。僕がこの設定を検討するのは、以下のパターンに絞っています。

  • 極端なデータ偏りがあるカラム: 特定のステータスやカテゴリが、全体の9割を占めているようなケース。
  • WHERE句によく登場するカラム: `status = ‘COMPLETED’` のように、クエリのフィルタ条件として頻出するカラム。
  • EXPLAIN ANALYZEで「見積もり(rows)」と「実測値(actual rows)」に大きな乖離がある場合: ここが一番の判断基準です。何桁もズレているなら、統計情報の不足を疑うのが定石です。

注意点:銀の弾丸ではない

一つだけ釘を刺しておくと、`SET STATISTICS` は万能薬ではありません。

例えば、「相関する複数のカラム」が原因でプランが崩れている場合、個別の統計精度を上げても限界があります。その場合は、`CREATE STATISTICS` を使って、カラム間の相関(マルチカラム統計)を定義する方が圧倒的に効果的です。

また、頻繁に値が書き換わるカラムに対して高すぎる統計精度を設定すると、`ANALYZE` の負荷が高まりすぎて、逆にシステム全体を重くしてしまうリスクもあります。

—

最後に:まずは「なぜそうなっているのか」を見る力を

クエリチューニングの面白いところは、PostgreSQLというエンジンの「思考プロセス」を覗き見できる点です。

`EXPLAIN ANALYZE` を叩いて、プランナがどう見積もっているかを眺める。そして、統計情報に手を加えて、それがどう変化するかを確かめる。この試行錯誤を繰り返していると、いつの間にか「このデータ分布なら、プランナはこう迷うはずだ」という直感が働くようになります。

もし今、特定のクエリで見積もりのズレに悩んでいるなら、まずは `SET STATISTICS` を試してみてください。きっと、PostgreSQLが「ああ、なるほど、そういう分布だったのか!」と本来の性能を発揮してくれるはずですよ。

それでは、また次回のチューニングでお会いしましょう。

コメント

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