前節で説明した通り、問い合わせプランナは、より良い問い合わせ計画を選択するために問い合わせによって取り出される行数の推定値を必要としています。この節では、システムがこの推定に使用する統計情報について簡単に説明します。
統計情報の 1 つの構成要素は、各テーブルとインデックスの項目の総数と、各テーブルとインデックスが占めるディスクブロック数です。この情報はpg_class の reltuples とrelpages 列に保持されます。以下のような問い合わせによりこれを参照することができます。
regression=# SELECT relname, relkind, reltuples, relpages FROM pg_class regression-# WHERE relname LIKE 'tenk1%'; relname | relkind | reltuples | relpages ---------------+---------+-----------+---------- tenk1 | r | 10000 | 233 tenk1_hundred | i | 10000 | 30 tenk1_unique1 | i | 10000 | 30 tenk1_unique2 | i | 10000 | 30 (4 rows)
ここで、tenk1 とそのインデックスには 10000 行が存在し、そして、(驚くには値しませんが)インデックスはテーブルよりもかなり小さなものであることが判ります。
効率をあげるため、reltuples とrelpages は処理の度に更新されず、したがって通常は(プランナの目的には十分な)概算値のみ所有しています。テーブルが作成された時これらはダミー値(現在それぞれ 1000 と 10)で初期化されます。これらは目下特定のコマンド、VACUUM、ANALYZE、CREATE INDEX によって更新されます。スタンドアローンの ANALYZE、つまり、VACUUM の一部ではないコマンドはテーブルの全ての行を読みませんので、reltuples の概算値を生成します。
ほとんどの問い合わせは、検証される行を制限する WHERE 句があることによって、テーブル内の行の一部のみを取り出します。 従って、プランナは WHERE 句の選択性、つまり、WHERE 条件の各句にどれだけの行が一致するか、を推定する必要があります。この処理に使用される情報は pg_statistic システムカタログ内に格納されます。pg_statistic 内のエントリは、ANALYZE と VACUUM ANALYZE コマンドによって更新され、また一から更新がかったとしても常に概算値になります。
統計情報を手作業で確認する場合、pg_statistic を直接参照するのではなく、pg_stats ビューを参照する方が良いでしょう。 pg_stats はより読み易くなるように設計されています。さらに、pg_stats は誰でも読みとることができますが、pg_statistic はスーパユーザのみ読みとることができます。(これは、非特権ユーザが統計情報から他の人間のテーブルの内容に関わる事項を読みとることを防止します。pg_stats ビューは現在のユーザが読みとることができるテーブルに関する行のみを表示するよう制限されています。)例えば、以下を行うことができます。
regression=# SELECT attname, n_distinct, most_common_vals FROM pg_stats WHERE tablename = 'road'; attname | n_distinct | most_common_vals ---------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- name | -0.467008 | {"I- 580 Ramp","I- 880 Ramp","Sp Railroad ","I- 580 ","I- 680 Ramp","I- 80 Ramp","14th St ","5th St ","Mission Blvd","I- 880 "} thepath | 20 | {"[(-122.089,37.71),(-122.0886,37.711)]"} (2 rows) regression=#
Table 10-1 に、pg_stats に存在する列を示します。
Table 10-1. pg_stats 列
名前 | 型 | 説明 |
---|---|---|
tablename | name | 列を持つテーブルの名前 |
attname | name | この行で示す列 |
null_frac | real | NULL である列エントリの割合 |
avg_width | integer | 列エントリの平均長 (バイト単位) |
n_distinct | real | ゼロより大きければ、列内の非重複値の推定数。ゼロより小さければ、非重複値の数を行の数で割った値を負にしたもの (負の形式は、ANALYZE が、非重複値の数がテーブルの成長につれて増加するとみなした場合に使用されます。正の形式は、その列に存在する可能性のある値が固定数であるとみなされた場合に使用されます)。例えば、-1 は列が一意であること、つまり、非重複値の数が行の数と同じであることを示します。 |
most_common_vals | text[] | 列内の最も一般的な値のリスト。(より一般的な値が存在しないとみなされた場 合は省略されます。) |
most_common_freqs | real[] | 最も一般的な値の頻度、つまり、その値それぞれが存在する数を行の総数を割った値のリスト。 |
histogram_bounds | text[] | 列の値をおよそ等しい分布に分割した値のリスト。most_common_vals はもしあれば、この度数計算から省かれます。(列のデータ型が< 演算子を持たない場合や、most_common_vals のリストが分布全体にあった場合は省略されます。 |
correlation | real | 列値の物理行順と論理的な順番間の統計相関値。この範囲は -1 から +1までです。 値が -1 か +1 に近ければ、列のインデックススキャンはディスクのランダムアクセスが減少しますので 0 に近いものよりも低コストであると推定されます。(列のデータ型が < 演算子を持たない場合は省略されます。) |
most_common_vals 内とhistogram_bounds配列のエントリの最大数は、ALTER TABLE SET STATISTICS コマンドによって列毎に設定することができます。現在のデフォルトの上限は 10 エントリです。この上限を上げることで、特に、非正規分布のデータを持つ列でより正確なプランナの推定が行われますが、pg_statistic により多くの容量が必要になり、多少推定計算にかかる時間が多くなります。反対に上限を下げることは、単純なデータ分布の列に対して順当です。