受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

CREATE STATISTICS

CREATE STATISTICS — 定义扩展统计信息

Synopsis

CREATE STATISTICS [ [ IF NOT EXISTS ] statistics_name ]
    ON ( expression )
    FROM table_name

CREATE STATISTICS [ [ IF NOT EXISTS ] statistics_name ]
    [ ( statistics_kind [, ... ] ) ]
    ON { column_name | ( expression ) }, { column_name | ( expression ) } [, ...]
    FROM table_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, 用于启用 MCV 列表。 如果省略该子句,则统计对象中会包含所有支持的统计种类。 如果统计信息定义中包含复杂表达式,而不仅仅是简单的列引用,则会自动构建单变量表达式统计信息。 更多信息参见 Section 14.2.2Section 70.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;

-- 匹配行的数量将被大大低估:
EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0);

CREATE STATISTICS s1 (dependencies) ON a, b FROM t1;

ANALYZE t1;

-- 现在行计数估计会更准确:
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;

-- 有效组合(在 MCV 列表中)
EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 1);

-- 无效组合(不在 MCV 列表中)
EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 2);

MCV 列表为规划器提供了关于表中经常出现的特定值的更详细信息, 同时也给出了表中未出现的值组合选择率的上界,因此在这两种情况下都能生成更好的估计。

创建表 t3,其中只有一个 timestamp 列,并对该列上的表达式运行查询。 如果没有扩展统计信息,规划器无法获知这些表达式的数据分布信息,只能使用默认估计值。 规划器也不会意识到,按月截断后的日期值完全由按天截断后的日期值决定。 然后在这两个表达式上构建表达式统计信息和 ndistinct 统计信息:

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;

-- 匹配行数会被严重低估:
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;

-- 在这对表达式上构建 ndistinct 统计(每个表达式的统计
-- 都会自动构建)
CREATE STATISTICS s3 (ndistinct) ON date_trunc('month', a), date_trunc('day', a) FROM t3;

ANALYZE t3;

-- 现在行数估计更准确:
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;

如果没有表达式统计信息和 ndistinct 统计信息,规划器就无法知道这些表达式的不同值个数, 只能依赖默认估计值。等值条件和范围条件都会被假定具有 0.5% 的选择率, 而表达式的不同值个数则被假定与该列相同(也就是唯一)。 这会导致前两个查询中的行数被严重低估。 此外,规划器没有关于这些表达式之间关系的信息,因此会假定两个 WHERE 条件和 GROUP BY 条件彼此独立,并将它们的选择率相乘, 从而对聚合查询中的分组数量作出严重高估。由于缺乏这些表达式的准确统计信息, 情况还会进一步恶化,迫使规划器对由列派生出来的表达式使用默认的 ndistinct 估计。 有了这些统计信息后,规划器就能识别出这些条件之间存在相关性,并得出准确得多的估计。

兼容性

SQL 标准中没有 CREATE STATISTICS 命令。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。