非常に単純なデータ集合で、多変量相関係数の例を示すことができます。 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;
14.2で説明されているように、pg_class
から得られるページ数と行数を使って、t
の濃度を決定できます。
SELECT relpages, reltuples FROM pg_class WHERE relname = 't'; relpages | reltuples ----------+----------- 45 | 10000
データの分布はとても単純です。各々の列にはわずか100の異なる値があるだけであり、かつ均一に分布しています。
次の例では、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
プランナは、この条件を調べ、この句の選択度を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
個別に選択度を見積もった結果、上記と同じ1%の見積もりとなります 次に、その条件が独立であると見なし、それらの選択度を掛けあわせ、最終的な選択度の見積もりをわずか0.01%であるとします その条件に一致する実際の行数は2桁多いので(100)、これはかなり過小見積もりです。
この問題は、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
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)
しかし、多変量統計がないと、二つの列についての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)
二つの列についての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)