规划器使用的统计信息

PostgreSQL 9.4.4 中文手册
上一页 | 上一级 | 章 14. 性能提升技巧 | 下一页

# 14.2. 规划器使用的统计信息

就像我们在上一节里展示的那样，查询规划器需要估计一个查询检索的行数， 这样才能选择正确的查询规划。本节就系统用于这些估计的统计进行一些描述。

统计的一个部分就是每个表和索引中的记录总数，以及每个表和索引占据的磁盘块数。 这个信息保存在`pg_class`表的 `reltuples`和`relpages`字段中。 我们可以用类似下面的查询检索这些信息：

    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)

我们在这里可以看到`tenk1`有10000行，它的索引也有这么多行，但是索引远比表小得多(很正常)。

出于效率考虑，`reltuples`和`relpages` 不是实时更新的， 因此它们通常包含可能有些过时的数值。它们被`VACUUM`, `ANALYZE`和几个DDL命令 (比如`CREATE INDEX`)更新。 `VACUUM`或者`ANALYZE`操作不扫描整个表（这是常见的情况）， 将逐步基于扫描表的部分更新`reltuples`数，从而产生一个近似值。 在任何情况下，规划器将把`pg_class`表里面的数值调整为和当前的物理表尺寸匹配， 以此获取一个更接近的近似值。

大多数查询只是检索表中行的一部分，因为它们有限制待查行的`WHERE`子句。 因此规划器需要对`WHERE`子句的选择性进行评估， 选择性也就是符合`WHERE`子句中每个条件的部分。 用于这个目的的信息存储在`pg_statistic`系统表中。 在`pg_statistic`中的记录是由`ANALYZE`和`VACUUM ANALYZE`命令更新的， 并且总是近似值，即使刚刚更新完也不例外。

除了直接查看`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)

需要注意的是两行显示为同一列，一个对应以`road`表(`inherited`=`t`)开头的完整继承层次。 而另一个只包含`road`表本身(`inherited`=`f`)。

通过`ANALYZE`命令存储在`pg_statistic`中的信息的数量， 特别是给每个字段用的`most_common_vals`和`histogram_bounds`数组上的最大记录数目 可以用`ALTER TABLE SET STATISTICS`命令设置， 或者是用运行时参数default_statistics_target进行全局设置。 目前缺省的限制值是 100个记录。 增加该限制值应该可以做出更准确的规划器估计，特别是对那些有不规则数据分布的字段而言， 代价是在`pg_statistic`里使用了更多空间，并且需要略微多一些的时间计算估计数值。相比之下， 比较低的限制可能更适合那些数据分布比较简单的字段。

有关规划器使用统计信息的进一步详情可参阅第 61 章。

上一页 | 起始页 | 下一页
使用`EXPLAIN` | 上一级 | 用明确的`JOIN`控制规划器