CREATE STATISTICS — 定义扩展统计信息
CREATE STATISTICS [ [ IF NOT EXISTS ]statistics_name] ON (expression) FROMtable_nameCREATE STATISTICS [ [ IF NOT EXISTS ]statistics_name] [ (statistics_kind[, ... ] ) ] ON {column_name| (expression) }, {column_name| (expression) } [, ...] FROMtable_name
CREATE STATISTICS 将创建一个新的扩展统计对象,用于跟踪有关指定表、外部表或物化视图的数据。该统计对象将被创建在当前数据库中,并由发出该命令的用户拥有。
CREATE STATISTICS 命令有两种基本形式。第一种形式允许为单个表达式收集单变量统计信息,其收益类似于表达式索引,但没有索引维护的开销。这种形式不允许指定统计信息的种类,因为各种统计信息种类仅针对多变量统计信息。该命令的第二种形式允许在多个列和/或表达式上收集多变量统计信息,并可以选择指定要包含哪些统计信息种类。这种形式还会自动对列表中包含的每个表达式收集单变量统计信息。
如果给出了模式名(例如 CREATE STATISTICS myschema.mystat ...),那么统计对象将被创建在指定的模式中。否则它将被创建在当前模式中。如果给出了统计对象的名称,那么该名称必须与同一模式中任何其他统计对象的名称不同。
IF NOT EXISTS 如果同名统计对象已经存在,则不抛出错误。在这种情况下会发出一个提示。注意这里只考虑统计对象的名称,而不考虑其定义的细节。当指定了 IF NOT EXISTS 时,必须给出统计信息的名称。
statistics_name要创建的统计对象的名称(可以选择用模式限定)。如果省略该名称,PostgreSQL 将根据父表的名称以及所定义的列名和/或表达式来选择一个合适的名称。
statistics_kind 要在这个统计对象中计算的一种多变量统计信息种类。当前支持的种类有 ndistinct(启用 n-distinct 统计信息)、dependencies(启用函数依赖统计信息)和 mcv(启用最常用值列表)。如果省略了这个子句,统计对象中将包含所有受支持的统计信息种类。如果统计信息定义中包含任何复杂表达式而不只是简单的列引用,则会自动构建单变量表达式统计信息。更多信息请参见 Section 14.2.2 和 Section 69.2。
column_name要被所计算的统计信息覆盖的一个表列的名称。只有在构建多变量统计信息时才允许使用。必须至少指定两个列名或表达式,并且它们的顺序无关紧要。
expression要被所计算的统计信息覆盖的一个表达式。它可用于在单个表达式上构建单变量统计信息,也可以作为多个列名和/或表达式列表的一部分来构建多变量统计信息。在后一种情况下,会自动为列表中的每个表达式分别构建单变量统计信息。
table_name包含统计信息所针对列的那个表的名称(可以选择用模式限定);有关继承和分区的处理方式的说明,请参见 ANALYZE。
必须是表的拥有者才能创建读取该表的统计对象。不过,统计对象一旦创建,其拥有权就与底层表无关了。
表达式统计信息是针对每个表达式的,类似于在表达式上创建索引,只是它避免了索引维护的开销。统计对象定义中的每个表达式都会自动构建表达式统计信息。
目前规划器在对表连接进行选择性估计时并不会使用扩展统计信息。这一限制可能会在 PostgreSQL 的未来版本中被移除。
创建带有两个函数依赖列的表 t1,也就是说,知道第一列中的值就足以确定另一列中的值。然后在这些列上构建函数依赖统计信息:
CREATE TABLE t1 (
a int,
b int
);
INSERT INTO t1 SELECT i/100, i/500
FROM generate_series(1,1000000) s(i);
ANALYZE t1;
-- the number of matching rows will be drastically underestimated:
EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0);
CREATE STATISTICS s1 (dependencies) ON a, b FROM t1;
ANALYZE t1;
-- now the row count estimate is more accurate:
EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0);
如果没有函数依赖统计信息,规划器会假设两个 WHERE 条件相互独立,并把它们的选择性相乘,从而得到一个过小的行数估计。有了这种统计信息,规划器就能识别出 WHERE 条件是冗余的,从而不会低估行数。
创建带有两个完全相关列(包含相同数据)的表 t2,并在这些列上建立一个 MCV 列表:
CREATE TABLE t2 (
a int,
b int
);
INSERT INTO t2 SELECT mod(i,100), mod(i,100)
FROM generate_series(1,1000000) s(i);
CREATE STATISTICS s2 (mcv) ON a, b FROM t2;
ANALYZE t2;
-- valid combination (found in MCV)
EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 1);
-- invalid combination (not found in MCV)
EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 2);
MCV 列表为规划器提供了关于表中经常出现的具体值的更详细信息,以及未出现在表中的值组合的选择性上界,使规划器在这两种情况下都能生成更好的估计。
创建只有一个 timestamp 列的表 t3,并在查询中使用该列上的表达式。在没有扩展统计信息的情况下,规划器对这些表达式的数据分布一无所知,只能使用默认估计值。规划器也不知道截断到月份的日期值完全由截断到天的日期值决定。然后在这两个表达式上构建表达式统计信息和 n-distinct 统计信息:
CREATE TABLE t3 (
a timestamp
);
INSERT INTO t3 SELECT i FROM generate_series('2020-01-01'::timestamp,
'2020-12-31'::timestamp,
'1 minute'::interval) s(i);
ANALYZE t3;
-- the number of matching rows will be drastically underestimated:
EXPLAIN ANALYZE SELECT * FROM t3
WHERE date_trunc('month', a) = '2020-01-01'::timestamp;
EXPLAIN ANALYZE SELECT * FROM t3
WHERE date_trunc('day', a) BETWEEN '2020-01-01'::timestamp
AND '2020-06-30'::timestamp;
EXPLAIN ANALYZE SELECT date_trunc('month', a), date_trunc('day', a)
FROM t3 GROUP BY 1, 2;
-- build ndistinct statistics on the pair of expressions (per-expression
-- statistics are built automatically)
CREATE STATISTICS s3 (ndistinct) ON date_trunc('month', a), date_trunc('day', a) FROM t3;
ANALYZE t3;
-- now the row count estimates are more accurate:
EXPLAIN ANALYZE SELECT * FROM t3
WHERE date_trunc('month', a) = '2020-01-01'::timestamp;
EXPLAIN ANALYZE SELECT * FROM t3
WHERE date_trunc('day', a) BETWEEN '2020-01-01'::timestamp
AND '2020-06-30'::timestamp;
EXPLAIN ANALYZE SELECT date_trunc('month', a), date_trunc('day', a)
FROM t3 GROUP BY 1, 2;
在没有表达式统计信息和 n-distinct 统计信息的情况下,规划器对表达式中不同值的数量一无所知,只能依赖默认估计值。等值条件和范围条件被假定具有 0.5% 的选择性,并且表达式中不同值的数量被假定与该列的相同(即唯一)。这会导致前两个查询中的行数被显著低估。此外,规划器对表达式之间的关系一无所知,因此它假定两个 WHERE 和 GROUP BY 条件相互独立,并把它们的选择性相乘,从而在该聚合查询中严重高估了分组数量。缺少针对表达式的准确统计信息进一步加剧了这一问题,迫使规划器对该表达式使用从该列的 n-distinct 推导出的默认 n-distinct 估计值。有了这样的统计信息,规划器就能识别出这些条件是相关的,并得到准确得多的估计。
SQL 标准中没有 CREATE STATISTICS 命令。