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

76.2. 多変量統計の例 #

<title>Multivariate Statistics Examples</title>

76.2.1. 関数従属性 #

<title>Functional Dependencies</title>

Multivariate correlation can be demonstrated with a very simple data set &mdash; a table with two columns, both containing the same values: 非常に単純なデータ集合で、多変量相関係数の例を示すことができます。 2つの列を持ち、両方の列が同じ値を持つテーブルです。

CREATE TABLE t (a INT, b INT);
INSERT INTO t SELECT i % 100, i % 100 FROM generate_series(1, 10000) s(i);
ANALYZE t;

As explained in <xref linkend="planner-stats"/>, the planner can determine cardinality of <structname>t</structname> using the number of pages and rows obtained from <structname>pg_class</structname>: 14.2で説明されているように、pg_classから得られるページ数と行数を使って、tの濃度を決定できます。

SELECT relpages, reltuples FROM pg_class WHERE relname = 't';

 relpages | reltuples
----------+-----------
       45 |     10000

The data distribution is very simple; there are only 100 distinct values in each column, uniformly distributed. データの分布はとても単純です。各々の列にはわずか100の異なる値があるだけであり、かつ均一に分布しています。

The following example shows the result of estimating a <literal>WHERE</literal> condition on the <structfield>a</structfield> column: 次の例では、a列に関するWHERE条件の見積もり結果を示しています。

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1;
                                 QUERY PLAN
-------------------------------------------------------------------​------------
 Seq Scan on t  (cost=0.00..170.00 rows=100 width=8) (actual rows=100 loops=1)
   Filter: (a = 1)
   Rows Removed by Filter: 9900

The planner examines the condition and determines the selectivity of this clause to be 1%. By comparing this estimate and the actual number of rows, we see that the estimate is very accurate (in fact exact, as the table is very small). Changing the <literal>WHERE</literal> condition to use the <structfield>b</structfield> column, an identical plan is generated. But observe what happens if we apply the same condition on both columns, combining them with <literal>AND</literal>: プランナは、この条件を調べ、この句の選択度を1%と決定しました。 この見積もりと、実際の行数を比較すると、見積もりは非常に正確であることがわかります。 (テーブルがとても小さいので、実際には見積もり通りです。) WHERE条件を変更してb列を使うようにすると、同じプランが生成されます。 では、AND条件でつないで、この二つの列に同じ条件を適用するとどうなるか見てみましょう。

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1;
                                 QUERY PLAN
-------------------------------------------------------------------​----------
 Seq Scan on t  (cost=0.00..195.00 rows=1 width=8) (actual rows=100 loops=1)
   Filter: ((a = 1) AND (b = 1))
   Rows Removed by Filter: 9900

The planner estimates the selectivity for each condition individually, arriving at the same 1% estimates as above. Then it assumes that the conditions are independent, and so it multiplies their selectivities, producing a final selectivity estimate of just 0.01%. This is a significant underestimate, as the actual number of rows matching the conditions (100) is two orders of magnitude higher. 個別に選択度を見積もった結果、上記と同じ1%の見積もりとなります 次に、その条件が独立であると見なし、それらの選択度を掛けあわせ、最終的な選択度の見積もりをわずか0.01%であるとします その条件に一致する実際の行数は2桁多いので(100)、これはかなり過小見積もりです。

This problem can be fixed by creating a statistics object that directs <command>ANALYZE</command> to calculate functional-dependency multivariate statistics on the two columns: この問題は、ANALYZEに二つの列について関数従属性多変量統計を計算させる、統計オブジェクトを作成することによって解決できます。

CREATE STATISTICS stts (dependencies) ON a, b FROM t;
ANALYZE t;
EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1;
                                  QUERY PLAN
-------------------------------------------------------------------​------------
 Seq Scan on t  (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1)
   Filter: ((a = 1) AND (b = 1))
   Rows Removed by Filter: 9900

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

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

A similar problem occurs with estimation of the cardinality of sets of multiple columns, such as the number of groups that would be generated by a <command>GROUP BY</command> clause. When <command>GROUP BY</command> lists a single column, the n-distinct estimate (which is visible as the estimated number of rows returned by the HashAggregate node) is very accurate: GROUP BY句が生成するグループ数のような、複数列の集合の濃度の見積もりについても、同様の問題が起きます。 GROUP BYの対象が単一の列なら、N個別値の推定(HashAggregateノードが返す推定行数で示されます)はとても正確です。

EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a;
                                       QUERY PLAN
-------------------------------------------------------------------​----------------------
 HashAggregate  (cost=195.00..196.00 rows=100 width=12) (actual rows=100 loops=1)
   Group Key: a
   ->  Seq Scan on t  (cost=0.00..145.00 rows=10000 width=4) (actual rows=10000 loops=1)

But without multivariate statistics, the estimate for the number of groups in a query with two columns in <command>GROUP BY</command>, as in the following example, is off by an order of magnitude: しかし、多変量統計がないと、二つの列についてのGROUP BY問い合わせにおけるグループ数の見積もりは、次の例のようにひと桁ずれてしまいます

EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b;
                                       QUERY PLAN
-------------------------------------------------------------------​-------------------------
 HashAggregate  (cost=220.00..230.00 rows=1000 width=16) (actual rows=100 loops=1)
   Group Key: a, b
   ->  Seq Scan on t  (cost=0.00..145.00 rows=10000 width=8) (actual rows=10000 loops=1)

By redefining the statistics object to include n-distinct counts for the two columns, the estimate is much improved: 二つの列についてのN個別値計数を含むように統計オブジェクトを再定義することにより、見積もりは大きく改善されます。

DROP STATISTICS stts;
CREATE STATISTICS stts (dependencies, ndistinct) ON a, b FROM t;
ANALYZE t;
EXPLAIN (ANALYZE, TIMING OFF) SELECT COUNT(*) FROM t GROUP BY a, b;
                                       QUERY PLAN
-------------------------------------------------------------------​-------------------------
 HashAggregate  (cost=220.00..221.00 rows=100 width=16) (actual rows=100 loops=1)
   Group Key: a, b
   ->  Seq Scan on t  (cost=0.00..145.00 rows=10000 width=8) (actual rows=10000 loops=1)

76.2.3. MCVリスト #

<title>MCV Lists</title>

As explained in <xref linkend="functional-dependencies"/>, functional dependencies are very cheap and efficient type of statistics, but their main limitation is their global nature (only tracking dependencies at the column level, not between individual column values). 76.2.1で説明したように、関数従属性は非常に安価で効率的な統計情報ですが、主要な制限はその大域的な性質です(列レベルだけでの従属性の追跡であり、個々の列の値の間のものではありません)。

This section introduces multivariate variant of <acronym>MCV</acronym> (most-common values) lists, a straightforward extension of the per-column statistics described in <xref linkend="row-estimation-examples"/>. These statistics address the limitation by storing individual values, but it is naturally more expensive, both in terms of building the statistics in <command>ANALYZE</command>, storage and planning time. この節ではMCV(最頻値)リストの多変量のもの、76.1で述べた行毎の統計情報の素直な拡張を導入します。 この統計情報は格納された個々の値による制限を解決しますが、ANALYZEでの統計情報の構築や容量や計画作成時間に関して当然より高価です。

Let's look at the query from <xref linkend="functional-dependencies"/> again, but this time with a <acronym>MCV</acronym> list created on the same set of columns (be sure to drop the functional dependencies, to make sure the planner uses the newly created statistics). 再び76.2.1の問い合わせを見てみましょう。ですが、今回は列の同じ集合に対してMCVリストを作ります(プランナが新しく作られた統計情報を確実に利用するよう、関数従属性を確実に削除してください)。

DROP STATISTICS stts;
CREATE STATISTICS stts2 (mcv) ON a, b FROM t;
ANALYZE t;
EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 1;
                                   QUERY PLAN
-------------------------------------------------------------------​------------
 Seq Scan on t  (cost=0.00..195.00 rows=100 width=8) (actual rows=100 loops=1)
   Filter: ((a = 1) AND (b = 1))
   Rows Removed by Filter: 9900

The estimate is as accurate as with the functional dependencies, mostly thanks to the table being fairly small and having a simple distribution with a low number of distinct values. Before looking at the second query, which was not handled by functional dependencies particularly well, let's inspect the <acronym>MCV</acronym> list a bit. 主に、テーブルがかなり小さく、異なる値の少ない単純な分布のおかげで、推定は関数従属性と同じくらい正確です。 関数従属性では特に上手く扱えない2番目の問い合わせを見る前に、MCVリストを少し調べてみましょう。

Inspecting the <acronym>MCV</acronym> list is possible using <function>pg_mcv_list_items</function> set-returning function. MCVを調べるのは、集合を返すpg_mcv_list_items関数でできます。

SELECT m.* FROM pg_statistic_ext join pg_statistic_ext_data on (oid = stxoid),
                pg_mcv_list_items(stxdmcv) m WHERE stxname = 'stts2';
 index |  values  | nulls | frequency | base_frequency
-------+----------+-------+-----------+----------------
     0 | {0, 0}   | {f,f} |      0.01 |         0.0001
     1 | {1, 1}   | {f,f} |      0.01 |         0.0001
   ...
    49 | {49, 49} | {f,f} |      0.01 |         0.0001
    50 | {50, 50} | {f,f} |      0.01 |         0.0001
   ...
    97 | {97, 97} | {f,f} |      0.01 |         0.0001
    98 | {98, 98} | {f,f} |      0.01 |         0.0001
    99 | {99, 99} | {f,f} |      0.01 |         0.0001
(100 rows)

This confirms there are 100 distinct combinations in the two columns, and all of them are about equally likely (1% frequency for each one). The base frequency is the frequency computed from per-column statistics, as if there were no multi-column statistics. Had there been any null values in either of the columns, this would be identified in the <structfield>nulls</structfield> column. これで、2つの列の100個の個別の組み合わせがあり、すべてほぼ同様に確からしい(それぞれ1%の頻度)ことが確かめられます。 基準となる頻度(base frequency)は、複数列の統計情報がないとして、列毎の統計情報から計算された頻度です。 列のどちらか一方にでもNULL値があれば、nulls列で見分けられます。

When estimating the selectivity, the planner applies all the conditions on items in the <acronym>MCV</acronym> list, and then sums the frequencies of the matching ones. See <function>mcv_clauselist_selectivity</function> in <filename>src/backend/statistics/mcv.c</filename> for details. 選択性を推定する場合、プランナはMCVリストの項目にすべての条件を適用してから、一致するものの頻度を合計します。 詳細はsrc/backend/statistics/mcv.cmcv_clauselist_selectivityを参照してください。

Compared to functional dependencies, <acronym>MCV</acronym> lists have two major advantages. Firstly, the list stores actual values, making it possible to decide which combinations are compatible. 関数従属性に比べて、MCVは主要な利点が2つあります。1つ目は、リストが実際の値を格納していることで、これによりどの組み合わせが適合するのか決定できます。

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a = 1 AND b = 10;
                                 QUERY PLAN
-------------------------------------------------------------------​--------
 Seq Scan on t  (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1)
   Filter: ((a = 1) AND (b = 10))
   Rows Removed by Filter: 10000

Secondly, <acronym>MCV</acronym> lists handle a wider range of clause types, not just equality clauses like functional dependencies. For example, consider the following range query for the same table: 2つ目は、MCVリストが、関数従属性のような等式句だけでなく、より広い範囲の形の句を扱うことです。 例えば、以下のような同じテーブルに対する範囲の問い合わせを考えてみましょう。

EXPLAIN (ANALYZE, TIMING OFF) SELECT * FROM t WHERE a <= 49 AND b > 49;
                                QUERY PLAN
-------------------------------------------------------------------​--------
 Seq Scan on t  (cost=0.00..195.00 rows=1 width=8) (actual rows=0 loops=1)
   Filter: ((a <= 49) AND (b > 49))
   Rows Removed by Filter: 10000