バージョンごとのドキュメント一覧

14.2. プランナで使用される統計情報 #

<title>Statistics Used by the Planner</title>

14.2.1. 単一列統計情報 #

<title>Single-Column Statistics</title>

As we saw in the previous section, the query planner needs to estimate the number of rows retrieved by a query in order to make good choices of query plans. This section provides a quick look at the statistics that the system uses for these estimates. 前節で説明した通り、問い合わせプランナは、より良い問い合わせ計画を選択するために問い合わせによって取り出される行数の推定値を必要としています。 本節では、システムがこの推定に使用する統計情報について簡単に説明します。

One component of the statistics is the total number of entries in each table and index, as well as the number of disk blocks occupied by each table and index. This information is kept in the table <link linkend="catalog-pg-class"><structname>pg_class</structname></link>, in the columns <structfield>reltuples</structfield> and <structfield>relpages</structfield>. We can look at it with queries similar to this one: 統計情報の1つの構成要素は、各テーブルとインデックスの項目の総数と、各テーブルとインデックスが占めるディスクブロック数です。 この情報はpg_classreltuplesrelpages列に保持されます。 以下のような問い合わせによりこれを参照することができます。

SELECT relname, relkind, reltuples, relpages
FROM pg_class
WHERE relname LIKE 'tenk1%';

       relname        | relkind | reltuples | relpages
----------------------+---------+-----------+----------
 tenk1                | r       |     10000 |      358
 tenk1_hundred        | i       |     10000 |       30
 tenk1_thous_tenthous | i       |     10000 |       30
 tenk1_unique1        | i       |     10000 |       30
 tenk1_unique2        | i       |     10000 |       30
(5 rows)

Here we can see that <structname>tenk1</structname> contains 10000 rows, as do its indexes, but the indexes are (unsurprisingly) much smaller than the table. ここで、tenk1とそのインデックスには10000行が存在し、そして、(驚くには値しませんが)インデックスはテーブルよりもかなり小さなものであることがわかります。

For efficiency reasons, <structfield>reltuples</structfield> and <structfield>relpages</structfield> are not updated on-the-fly, and so they usually contain somewhat out-of-date values. They are updated by <command>VACUUM</command>, <command>ANALYZE</command>, and a few DDL commands such as <command>CREATE INDEX</command>. A <command>VACUUM</command> or <command>ANALYZE</command> operation that does not scan the entire table (which is commonly the case) will incrementally update the <structfield>reltuples</structfield> count on the basis of the part of the table it did scan, resulting in an approximate value. In any case, the planner will scale the values it finds in <structname>pg_class</structname> to match the current physical table size, thus obtaining a closer approximation. 効率を上げるため、reltuplesrelpagesは処理の度には更新されず、したがって通常は多少古い値のみ所有しています。 これらはVACUUMANALYZECREATE INDEXなどの一部のDDLコマンドによって更新されます。 テーブル全体をスキャンしないVACUUMANALYZE操作(一般的な状況です)は、スキャンされたテーブルの部分に基づいてreltuples値を漸次更新し、概算値を生成します。 いずれの場合でもプランナは、現在の物理的なテーブルサイズに合わせるためにpg_classから検索した値を調整して、より高精度な近似値を得ます。

Most queries retrieve only a fraction of the rows in a table, due to <literal>WHERE</literal> clauses that restrict the rows to be examined. The planner thus needs to make an estimate of the <firstterm>selectivity</firstterm> of <literal>WHERE</literal> clauses, that is, the fraction of rows that match each condition in the <literal>WHERE</literal> clause. The information used for this task is stored in the <link linkend="catalog-pg-statistic"><structname>pg_statistic</structname></link> system catalog. Entries in <structname>pg_statistic</structname> are updated by the <command>ANALYZE</command> and <command>VACUUM ANALYZE</command> commands, and are always approximate even when freshly updated. ほとんどの問い合わせは、検証される行を制限するWHERE句によって、テーブル内の行の一部のみを取り出します。 したがって、プランナはWHERE句の選択性、つまりWHERE句の各条件にどれだけの行が一致するかを推定する必要があります。 この処理に使用される情報はpg_statisticシステムカタログ内に格納されます。 pg_statistic内の項目は、ANALYZEVACUUM ANALYZEコマンドによって更新され、また1から更新がかかったとしても常に概算値になります。

Rather than look at <structname>pg_statistic</structname> directly, it's better to look at its view <link linkend="view-pg-stats"><structname>pg_stats</structname></link> when examining the statistics manually. <structname>pg_stats</structname> is designed to be more easily readable. Furthermore, <structname>pg_stats</structname> is readable by all, whereas <structname>pg_statistic</structname> is only readable by a superuser. (This prevents unprivileged users from learning something about the contents of other people's tables from the statistics. The <structname>pg_stats</structname> view is restricted to show only rows about tables that the current user can read.) For example, we might do: 統計情報を手作業で確認する場合、pg_statisticを直接参照するのではなく、pg_statsビューを参照する方が良いでしょう。 pg_statsはより読みやすくなるように設計されています。 さらに、pg_statsは誰でも読み取ることができますが、pg_statisticはスーパーユーザのみ読み取ることができます。 (これは、非特権ユーザが統計情報から他人のテーブルの内容に関わる事項を読み取ることを防止します。 pg_statsビューは現在のユーザが読み取ることができるテーブルに関する行のみを表示するよう制限されています。) 例えば、以下を行うことができます。

SELECT attname, inherited, n_distinct,
       array_to_string(most_common_vals, E'\n') as most_common_vals
FROM pg_stats
WHERE tablename = 'road';

 attname | inherited | n_distinct |          most_common_vals
---------+-----------+------------+------------------------------------
 name    | f         |  -0.363388 | I- 580                        Ramp+
         |           |            | I- 880                        Ramp+
         |           |            | Sp Railroad                       +
         |           |            | I- 580                            +
         |           |            | I- 680                        Ramp
 name    | t         |  -0.284859 | I- 880                        Ramp+
         |           |            | I- 580                        Ramp+
         |           |            | I- 680                        Ramp+
         |           |            | I- 580                            +
         |           |            | State Hwy 13                  Ramp
(2 rows)

Note that two rows are displayed for the same column, one corresponding to the complete inheritance hierarchy starting at the <literal>road</literal> table (<literal>inherited</literal>=<literal>t</literal>), and another one including only the <literal>road</literal> table itself (<literal>inherited</literal>=<literal>f</literal>). 同じ列に対して2行が表示されていることに注意してください。 1つはroadテーブルが始まる継承階層(inherited=t)全体に相当し、もう1つはroadテーブル自身(inherited=f)のみを含むものです。

The amount of information stored in <structname>pg_statistic</structname> by <command>ANALYZE</command>, in particular the maximum number of entries in the <structfield>most_common_vals</structfield> and <structfield>histogram_bounds</structfield> arrays for each column, can be set on a column-by-column basis using the <command>ALTER TABLE SET STATISTICS</command> command, or globally by setting the <xref linkend="guc-default-statistics-target"/> configuration variable. The default limit is presently 100 entries. Raising the limit might allow more accurate planner estimates to be made, particularly for columns with irregular data distributions, at the price of consuming more space in <structname>pg_statistic</structname> and slightly more time to compute the estimates. Conversely, a lower limit might be sufficient for columns with simple data distributions. ANALYZEによりpg_statisticに格納される情報量、具体的には、それぞれの列に対するmost_common_vals内とhistogram_bounds配列のエントリの最大数は、ALTER TABLE SET STATISTICSコマンドによって列ごとに、default_statistics_target設定パラメータを設定することによってグローバルに設定することができます。 現在のデフォルトの上限は100エントリです。 この上限を上げることで、特に、少し変わったデータ分布を持つ列でより正確なプランナの推定が行われますが、pg_statisticにより多くの容量が必要になり、多少推定計算にかかる時間が多くなります。 反対に上限を下げることは、単純なデータ分布の列に対して順当です。

Further details about the planner's use of statistics can be found in <xref linkend="planner-stats-details"/>. プランナによる統計情報の使用に関する詳細については第76章を参照してください。

14.2.2. 拡張統計情報 #

<title>Extended Statistics</title>

It is common to see slow queries running bad execution plans because multiple columns used in the query clauses are correlated. The planner normally assumes that multiple conditions are independent of each other, an assumption that does not hold when column values are correlated. Regular statistics, because of their per-individual-column nature, cannot capture any knowledge about cross-column correlation. However, <productname>PostgreSQL</productname> has the ability to compute <firstterm>multivariate statistics</firstterm>, which can capture such information. 問い合わせ句で使われている複数列に相関性があることにより、悪い実行計画を実行する遅いクエリがしばしば観察されます。 プランナは通常複数の条件がお互いに独立であるとみなしますが、列の値に相関性がある場合はそれは成り立ちません。 通常の列ごとの統計情報は、それが個々の列ごとであるという性質上、列をまたがる相関性に関する知識を把握することはできません。 しかしながら、PostgreSQLは、多変量統計情報を計算することができ、それによってそうした情報を把握することができます。

Because the number of possible column combinations is very large, it's impractical to compute multivariate statistics automatically. Instead, <firstterm>extended statistics objects</firstterm>, more often called just <firstterm>statistics objects</firstterm>, can be created to instruct the server to obtain statistics across interesting sets of columns. 列の組み合わせの数は非常に大きいため、自動的に多変量統計情報を計算するのは現実的ではありません。 代わりに、サーバが興味のある列の集合にまたがる統計情報を得るように指示する目的で、拡張統計情報オブジェクト(しばしば単に統計情報オブジェクトと呼ばれます)を作成することができます。

Statistics objects are created using the <link linkend="sql-createstatistics"><command>CREATE STATISTICS</command></link> command. Creation of such an object merely creates a catalog entry expressing interest in the statistics. Actual data collection is performed by <command>ANALYZE</command> (either a manual command, or background auto-analyze). The collected values can be examined in the <link linkend="catalog-pg-statistic-ext-data"><structname>pg_statistic_ext_data</structname></link> catalog. 統計情報オブジェクトはCREATE STATISTICSで作成します。 そうしたオブジェクトを作っても、単に統計情報として興味があることを示すカタログエントリが作られるだけです。 実際のデータ収集は、ANALYZE (手動のコマンドを起動あるいはバックグラウンドでの自動ANALYZE)が行います。 収集したデータは、pg_statistic_ext_dataカタログで参照することができます。

<command>ANALYZE</command> computes extended statistics based on the same sample of table rows that it takes for computing regular single-column statistics. Since the sample size is increased by increasing the statistics target for the table or any of its columns (as described in the previous section), a larger statistics target will normally result in more accurate extended statistics, as well as more time spent calculating them. 通常の単一列統計情報の計算に使うのと同じテーブル行のサンプルに基づき、ANALYZEは、拡張統計情報を計算します。 (前節で述べたように)テーブルあるいはそのテーブルの対象となる列統計情報の増やすと、サンプルのサイズも増えるので、より大きな統計情報の対象を使うと、通常、より精度の高い拡張統計情報を得られますが、計算に費やす時間も増えます。

The following subsections describe the kinds of extended statistics that are currently supported. 次の節では、現在サポートしている拡張統計情報の種類を説明します。

14.2.2.1. 関数従属性 #

<title>Functional Dependencies</title>

The simplest kind of extended statistics tracks <firstterm>functional dependencies</firstterm>, a concept used in definitions of database normal forms. We say that column <structfield>b</structfield> is functionally dependent on column <structfield>a</structfield> if knowledge of the value of <structfield>a</structfield> is sufficient to determine the value of <structfield>b</structfield>, that is there are no two rows having the same value of <structfield>a</structfield> but different values of <structfield>b</structfield>. In a fully normalized database, functional dependencies should exist only on primary keys and superkeys. However, in practice many data sets are not fully normalized for various reasons; intentional denormalization for performance reasons is a common example. Even in a fully normalized database, there may be partial correlation between some columns, which can be expressed as partial functional dependency. もっとも単純な拡張統計情報は、データベースの正規形の定義で使われる考え方である、関数従属性を追跡します。 aの値に関する知識がbの値を決定するのに十分であるとき、列bは列aに関数的に従属していると言います。 これはすなわち、同じaの値を持ちながら、異なるbの値を持つ二つの行は存在しないということです。 完全に正規化されたデータベースでは、関数従属性は主キーと超キーにのみ存在します。 実際には様々な理由でデータの集合は完全には正規化されません。 性能上の理由により非正規化するというのが典型的な例です。 完全に正規化されたデータベースにおいても、ある列の間に部分的な相関関係が存在することがあり、これは部分的関数従属性として表現されます。

The existence of functional dependencies directly affects the accuracy of estimates in certain queries. If a query contains conditions on both the independent and the dependent column(s), the conditions on the dependent columns do not further reduce the result size; but without knowledge of the functional dependency, the query planner will assume that the conditions are independent, resulting in underestimating the result size. ある問い合わせでは、関数従属性が存在することが見積もりの精度に直接影響を与えます。 問い合わせに独立した列と依存する列の両方に関する条件が含まれていると、依存する列に関する条件はそれ以上結果サイズを小さくしません。 しかし関数従属性に関する知識がなければ、クエリプランナはそれらの条件が独立であると見なし、結果サイズの過少見積もりすることになります。

To inform the planner about functional dependencies, <command>ANALYZE</command> can collect measurements of cross-column dependency. Assessing the degree of dependency between all sets of columns would be prohibitively expensive, so data collection is limited to those groups of columns appearing together in a statistics object defined with the <literal>dependencies</literal> option. It is advisable to create <literal>dependencies</literal> statistics only for column groups that are strongly correlated, to avoid unnecessary overhead in both <command>ANALYZE</command> and later query planning. プランナに関数従属性について知らせるために、ANALYZEは列をまたがる依存性の強さを収集することができます。 すべての列の集合間の依存性度合いを調査するのは、受け入れられないほど高価になります。 そこでデータ収集は、dependenciesオプションで定義された統計情報オブジェクトの中に一緒に現れた列のグループに制限されます。 ANALYZEおよび後々のクエリプランニングにおける不必要なオーバーヘッドを避けるために、強い相関関係のある列のグループのみを対象に、dependencies統計情報を作成することをお勧めします。

Here is an example of collecting functional-dependency statistics: 関数従属性統計情報の収集例です。

CREATE STATISTICS stts (dependencies) ON city, zip FROM zipcodes;

ANALYZE zipcodes;

SELECT stxname, stxkeys, stxddependencies
  FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid)
  WHERE stxname = 'stts';
 stxname | stxkeys |             stxddependencies
---------+---------+------------------------------------------
 stts    | 1 5     | {"1 => 5": 1.000000, "5 => 1": 0.423130}
(1 row)

Here it can be seen that column 1 (zip code) fully determines column 5 (city) so the coefficient is 1.0, while city only determines zip code about 42% of the time, meaning that there are many cities (58%) that are represented by more than a single ZIP code. ここでは、列1(zip code)が完全に列5(city)を決定しているので、係数は1.0です。 一方、cityはzip codeを42%しか決定していないので、一つ以上のzip codeで表現されている多くのcity(58%)が存在するということになります。

When computing the selectivity for a query involving functionally dependent columns, the planner adjusts the per-condition selectivity estimates using the dependency coefficients so as not to produce an underestimate. 関数従属する列を伴うクエリの選択率を計算する際、過小評価を行わないように、プランナは依存性係数を使って条件ごとの選択率を調整します。

14.2.2.1.1. 関数従属性の制限事項 #
<title>Limitations of Functional Dependencies</title>

Functional dependencies are currently only applied when considering simple equality conditions that compare columns to constant values, and <literal>IN</literal> clauses with constant values. They are not used to improve estimates for equality conditions comparing two columns or comparing a column to an expression, nor for range clauses, <literal>LIKE</literal> or any other type of condition. 今のところ、列と定数を比較する単純な等価条件と、定数のIN句を考慮する際にしか関数従属性は適用されません。 二つの列を比較する、あるいは列を式と比較する等価条件、範囲句、LIKEその他の条件の見積もりを改善するのには使われません。

When estimating with functional dependencies, the planner assumes that conditions on the involved columns are compatible and hence redundant. If they are incompatible, the correct estimate would be zero rows, but that possibility is not considered. For example, given a query like 関数従属性を含めた見積もりでは、プランナは関係する列に対する複数の条件が同時に成り立つ、つまり冗長であるとみなします。 それらの条件が同時に成り立たなければ、正しい見積もりは0行となりますが、その可能性は考慮されません。 たとえば次のクエリを見てください。

SELECT * FROM zipcodes WHERE city = 'San Francisco' AND zip = '94105';

the planner will disregard the <structfield>city</structfield> clause as not changing the selectivity, which is correct. However, it will make the same assumption about プランナは、選択率が変わらないという正しい推定に基づきcity句を無視します。 しかし、これを満たす行が0行であるにもかかわらず、次の問い合わせでも同じ推測をします。

SELECT * FROM zipcodes WHERE city = 'San Francisco' AND zip = '90210';

even though there will really be zero rows satisfying this query. Functional dependency statistics do not provide enough information to conclude that, however. 関数従属性統計情報は、これを結論付けるだけの十分な情報を提供しません。

In many practical situations, this assumption is usually satisfied; for example, there might be a GUI in the application that only allows selecting compatible city and ZIP code values to use in a query. But if that's not the case, functional dependencies may not be a viable option. 多くの実用的な場合には、この前提は通常満たされます。 たとえば、あるアプリケーションには、クエリの中で両立するcityとZIP codeだけを許すGUIが備わっているかもしれません。 もしそうでなければ、関数従属性は実行可能なオプションではないかもしれません。

14.2.2.2. 多変量N個別値計数 #

<title>Multivariate N-Distinct Counts</title>

Single-column statistics store the number of distinct values in each column. Estimates of the number of distinct values when combining more than one column (for example, for <literal>GROUP BY a, b</literal>) are frequently wrong when the planner only has single-column statistical data, causing it to select bad plans. 単一列統計情報は、それぞれの列で異なる値の数を保持します。 たとえば、GROUP BY a, bのように、二つ以上の列を組み合わせての異なる値の数の見積もりは、プランナに単一列の統計情報だけしか与えられない場合は、しばしば間違ったものになり、プランナは悪いプランの選択をしてしまいます。

To improve such estimates, <command>ANALYZE</command> can collect n-distinct statistics for groups of columns. As before, it's impractical to do this for every possible column grouping, so data is collected only for those groups of columns appearing together in a statistics object defined with the <literal>ndistinct</literal> option. Data will be collected for each possible combination of two or more columns from the set of listed columns. 見積もり改善のために、列のグループに対してANALYZEはN個別統計情報を収集することができます。 以前述べたのと同様に、可能なすべての列のグループに対してこれを行なうのは現実的ではありません。 ndistinctオプションで定義された統計オブジェクト中に一緒に現れる列のグループに対してのみデータを 収集します。 列リストの中から、可能な二つ以上の列の組み合わせそれぞれに対してデータが収集されます。

Continuing the previous example, the n-distinct counts in a table of ZIP codes might look like the following: 先ほどの例の続きで、ZIP codeのテーブルのN個別値計数は次のようになります。

CREATE STATISTICS stts2 (ndistinct) ON city, state, zip FROM zipcodes;

ANALYZE zipcodes;

SELECT stxkeys AS k, stxdndistinct AS nd
  FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid)
  WHERE stxname = 'stts2';
-[ RECORD 1 ]------------------------------------------------------​--
k  | 1 2 5
nd | {"1, 2": 33178, "1, 5": 33178, "2, 5": 27435, "1, 2, 5": 33178}
(1 row)

This indicates that there are three combinations of columns that have 33178 distinct values: ZIP code and state; ZIP code and city; and ZIP code, city and state (the fact that they are all equal is expected given that ZIP code alone is unique in this table). On the other hand, the combination of city and state has only 27435 distinct values. この例では、33178の異なる値を持つ列の組み合わせが三つあることを示しています。 ZIP codeとstate、ZIP codeとcity、cityとstateです。(これらが等しいという事実は、ZIP codeだけがテーブル中でユニークであることから期待されます。) 一方、cityとstateの組み合わせには、27435だけの異なる値があります。

It's advisable to create <literal>ndistinct</literal> statistics objects only on combinations of columns that are actually used for grouping, and for which misestimation of the number of groups is resulting in bad plans. Otherwise, the <command>ANALYZE</command> cycles are just wasted. グループ化で実際に使用する列の組み合わせで、かつグループ数の見積もり間違いによって悪いプランをもたらすものに対してだけ、ndistinct統計情報オブジェクトを作ることをお勧めします。 さもないと、ANALYZEサイクルは単に無駄になります。

14.2.2.3. 多変量MCVリスト #

<title>Multivariate MCV Lists</title>

Another type of statistic stored for each column are most-common value lists. This allows very accurate estimates for individual columns, but may result in significant misestimates for queries with conditions on multiple columns. 列ごとに格納される別なタイプの統計値は最頻値リスト(most-common value list)です。 個々の列ごとには非常に正確な推測を可能にしますが、複数列に渡る条件を持つ問い合わせについては重大な誤った推定をもたらすことがあります。

To improve such estimates, <command>ANALYZE</command> can collect MCV lists on combinations of columns. Similarly to functional dependencies and n-distinct coefficients, it's impractical to do this for every possible column grouping. Even more so in this case, as the MCV list (unlike functional dependencies and n-distinct coefficients) does store the common column values. So data is collected only for those groups of columns appearing together in a statistics object defined with the <literal>mcv</literal> option. こうした推定を改善するために、列の組み合わせのMCVリストをANALYZEで収集することができます。 関数従属性とN個別値係数同様、考えられるすべての列のグループに対してこれを行うのは実用的ではありません。 MCVリストでは(関数従属性とN個別値係数と違って)列の頻値を格納するのでなおさらです。 ですからmcvオプションで定義された統計情報オブジェクト中に共通して現れる列のグループのデータだけが収集されます。

Continuing the previous example, the MCV list for a table of ZIP codes might look like the following (unlike for simpler types of statistics, a function is required for inspection of MCV contents): 前述の例を続けましょう。ZIPコードのテーブルのMCVリストは次のようになるでしょう。(単純な形式の統計情報とは違って、MCVの内容を解析する関数が必要になります)

CREATE STATISTICS stts3 (mcv) ON city, state FROM zipcodes;

ANALYZE zipcodes;

SELECT m.* FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid),
                pg_mcv_list_items(stxdmcv) m WHERE stxname = 'stts3';

 index |         values         | nulls | frequency | base_frequency
-------+------------------------+-------+-----------+----------------
     0 | {Washington, DC}       | {f,f} |  0.003467 |        2.7e-05
     1 | {Apo, AE}              | {f,f} |  0.003067 |        1.9e-05
     2 | {Houston, TX}          | {f,f} |  0.002167 |       0.000133
     3 | {El Paso, TX}          | {f,f} |     0.002 |       0.000113
     4 | {New York, NY}         | {f,f} |  0.001967 |       0.000114
     5 | {Atlanta, GA}          | {f,f} |  0.001633 |        3.3e-05
     6 | {Sacramento, CA}       | {f,f} |  0.001433 |        7.8e-05
     7 | {Miami, FL}            | {f,f} |    0.0014 |          6e-05
     8 | {Dallas, TX}           | {f,f} |  0.001367 |        8.8e-05
     9 | {Chicago, IL}          | {f,f} |  0.001333 |        5.1e-05
   ...
(99 rows)

This indicates that the most common combination of city and state is Washington in DC, with actual frequency (in the sample) about 0.35%. The base frequency of the combination (as computed from the simple per-column frequencies) is only 0.0027%, resulting in two orders of magnitude under-estimates. これによると市と州のもっとも頻度の高い組み合わせはDCのWashingtonで、(サンプルにおける)実際の頻度は約0.35%でした。 比較の基準となる組み合わせの頻度(単純な列ごとの頻度から計算されたもの)はたった0.0027%で、2桁の過少見積になっています。

It's advisable to create <acronym>MCV</acronym> statistics objects only on combinations of columns that are actually used in conditions together, and for which misestimation of the number of groups is resulting in bad plans. Otherwise, the <command>ANALYZE</command> and planning cycles are just wasted. そのグループの誤推定値が間違った計画をもたらしてしまうような、条件の中で実際に一緒に使われる列の組み合わせについてのみMCV統計情報オブジェクトを作成することが望ましいです。 さもないと、ANALYZEとプラン処理は単に無駄になってしまいます。