Instiq
第2章 · 性能監視·v1.0.0·更新 2026/7/8·読了目安 約13分

変更要約: 初版(主題G2・G2.1〜G2.4)

2.2テーブル/カラム統計情報

この節の要点

プランナが実行計画を選ぶ根拠となるpg_statisticpg_statsを学びます。カラムごとのnull_fracn_distinctmost_common_valsmost_common_freqshistogram_boundscorrelationの意味と、統計の精度を左右するdefault_statistics_target、キャッシュ規模の見積もりに使うeffective_cache_size、複数カラム相関を捉える拡張統計(CREATE STATISTICSpg_statistic_ext)を押さえます。

PostgreSQLのプランナは、実際にクエリを実行してみるまで結果行数が分からない代わりに、過去にANALYZEで収集した統計情報から見積もるというアプローチを取ります。この見積もりの精度が実行計画の良し悪しを直接左右するため、統計情報がどのカラムでどう保存され、何が精度を決めるかを理解することは、EXPLAINを読み解く前提知識になります。

2.2.1pg_statistic と pg_stats

  • pg_statisticANALYZEが収集した生の統計情報を格納するシステムカタログ。列名がstanullfracのように型付き配列で格納され直接読みづらいため、実務では読みやすい形に変換されたpg_stats(ビュー)を参照するのが基本。pg_statsはテーブル所有者や権限を持つロールのみ全カラムを閲覧できる。
  • null_frac=そのカラムがNULLである行の割合。n_distinct異なる値の推定個数(正の値=絶対数、負の値=行数に対する比率。例えば-0.5は「行数の半分がユニーク値」を意味し、主キーに近いカラムほど-1に近づく)。
  • most_common_vals(MCV)=出現頻度が高い値のリストmost_common_freqs=それぞれの出現頻度(対で並ぶ)。プランナはWHERE col = 定数のようなクエリで、その定数がMCVに含まれていれば対応する頻度をそのまま使い、含まれていなければ残りの分布から推定する。histogram_bounds=MCVに含まれない値の分布を表す等頻度ヒストグラムの境界値(範囲述語WHERE col > 定数の選択率推定に使う)。correlationカラムの値の並び順と物理的な格納順の相関(-1〜1。1に近いほど物理順とソート順が一致し、Index Scanがディスク上でも順序よく読めるため有利になる)。

2.2.2統計精度と拡張統計

  • default_statistics_target=ANALYZEが各カラムについて収集するMCV/ヒストグラムの詳細度(既定100)を制御するパラメータ。値を上げるほどMCVやヒストグラムの分割数が増え見積もり精度が上がる代わりにANALYZE自体のコストとpg_statisticのサイズが増える。カラム単位でALTER TABLE ... ALTER COLUMN ... SET STATISTICS nにより個別上書きも可能。
  • effective_cache_sizeOSのファイルシステムキャッシュも含めた、実質的に使えるキャッシュ総量の見積もりをプランナに伝えるパラメータ(実際にメモリを確保するわけではない)。この値が大きいほど、プランナは「データはキャッシュに乗っている可能性が高い」と判断し、Index Scanを選好しやすくなる。
  • 拡張統計=カラム単体の統計では捉えられない複数カラム間の相関(例:都道府県と市区町村のように片方が決まればもう片方の分布が偏る関係)を明示的に登録する仕組み。CREATE STATISTICS文で対象カラムと種類(functional dependencies/ndistinct/mcv)を指定して作成し、定義はpg_statistic_extカタログに登録され、ANALYZE後の実データはpg_statistic_ext_data(読みやすくは pg_stats_ext ビュー)に格納される。相関を無視した独立性の仮定による見積もり誤差を補正する目的で使う。
試験ポイント

「n_distinctの負値は行数に対する比率(主キー近似で-1に近い)」「most_common_vals/most_common_freqsは対で並ぶ」「correlationが1に近いほどIndex Scanが有利」「default_statistics_targetを上げると精度は上がるがANALYZEコストも増える」「複数カラムの相関はCREATE STATISTICSで拡張統計を作らないと捉えられない」が最頻出です。pg_statisticは生データ・pg_statsは読みやすいビューという役割分担も繰り返し出ます。

統計の粗さがどう実害に転じるかを、実例で追ってみましょう。ある大規模なordersテーブルで、statusカラムにpending/shipped/cancelledの3値しかないのに、実行計画が期待に反してSeq Scanを選ぶ、という相談は典型的です。SELECT * FROM pg_stats WHERE tablename='orders' AND attname='status';を確認すると、most_common_valsに3値が入りmost_common_freqsも妥当な比率であれば、プランナの見積もり自体は正確であり、WHERE status = 'pending'が全体の40%を占めるような高頻度値であれば、そもそもインデックスを使うよりSeq Scanの方が速いという正しい判断の可能性が高いと分かります。逆に、統計が古い(last_analyzeが数週間前)ためにMCVの比率が実態とズレている場合は、ANALYZE orders;を再実行して統計を更新するのが第一の対処です。それでも精度が足りない列(値の種類は少ないが分布の偏りが激しい、あるいはカーディナリティが非常に高いカラム)には、ALTER TABLE orders ALTER COLUMN customer_id SET STATISTICS 500;のように個別にdefault_statistics_targetを上書きしてANALYZEし直すことで、ヒストグラムやMCVの分解能を上げられます。さらに、customer_idregionのように論理的に強く相関する2カラムの組み合わせを条件に含むクエリでは、個別カラムの統計だけでは「両方の条件を満たす行数」を過小/過大評価しやすいため、CREATE STATISTICS orders_cust_region_stat (dependencies) ON customer_id, region FROM orders;のように拡張統計を作成し、ANALYZE後にpg_statistic_extへ反映させることで、複数条件を組み合わせたWHERE句の見積もり精度を底上げできます。「まず統計を疑い、次にANALYZEし、それでも足りなければ精度そのものを上げる」という段階的なアプローチが実務の定石です。

項目意味用途
null_fracNULLである行の割合IS NULL述語の選択率推定
n_distinct異なる値の推定数(負値は比率)カーディナリティ推定
most_common_vals/freqs頻出値と頻度の対等値述語の選択率推定
histogram_bounds等頻度ヒストグラムの境界範囲述語の選択率推定
correlation物理順とソート順の相関(-1〜1)Index Scanの有利さの判断
注意

ひっかけ: 「n_distinctは常に正の絶対数である」は誤りです。負の値は行数に対する比率を表し、主キーやユニーク制約に近いカラムほど-1に近づきます。また「複数カラムにまたがる相関はdefault_statistics_targetを上げれば自動的に捉えられる」も誤り=default_statistics_targetは単一カラムの精度を左右するパラメータで、カラム間相関を捉えるには別途CREATE STATISTICSで拡張統計を明示的に作成する必要があります。

pg_statistic/pg_statsとその代表列(null_frac/n_distinct/histogram_bounds等)、default_statistics_target、CREATE STATISTICSによる拡張統計を示す図。
default_statistics_target が pg_stats の精度を左右する

2.2.3この節のまとめ

  • pg_statistic=生データ・pg_stats=読みやすいビューnull_frac/n_distinct(負値=比率)/most_common_vals+freqs/histogram_bounds/correlationでプランナの見積もりが決まる
  • default_statistics_target=統計の詳細度(列単位で上書き可)effective_cache_size=キャッシュ見積もり複数カラム相関はCREATE STATISTICSで拡張統計(pg_statistic_ext)

進捗の記録にはログインが必要です。

理解度チェック

(軽い確認用)

Q1. pg_stats で customer_id カラムの n_distinct が -0.98 と表示されている。この値の正しい解釈は?

Q2. ordersテーブルで customer_id と region の組み合わせ条件を持つクエリの行数見積もりが実態と大きくずれている。両カラムには強い論理的相関がある。最も適切な対処は?

Q3. ある頻度分布が大きく偏ったカラムで、既定のANALYZE精度では選択率の見積もり誤差が大きい。ANALYZEのコスト増を許容してでも当該カラムの精度だけを上げたい。適切な方法は?

理解度を確認第2章「性能監視」の問題を解く