🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 14.2\. 规划器使用的统计信息 就像我们在上一节里展示的那样,查询规划器需要估计一个查询检索的行数, 这样才能选择正确的查询规划。本节就系统用于这些估计的统计进行一些描述。 统计的一个部分就是每个表和索引中的记录总数,以及每个表和索引占据的磁盘块数。 这个信息保存在[`pg_class`](#calibre_link-578)表的 `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`](#calibre_link-769)系统表中。 在`pg_statistic`中的记录是由`ANALYZE`和`VACUUM ANALYZE`命令更新的, 并且总是近似值,即使刚刚更新完也不例外。 除了直接查看`pg_statistic`之外, 我们手工检查统计的时候最好查看[`pg_stats`](#calibre_link-771)的视图。 `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) ``` 需要注意的是两行显示为同一列,1对应在`road`表(`inherited`=`t`)开头的完整继承层次结构。 而另一个只包含`road`表本身(`inherited`=`f`)。 在`pg_statistic`中通过`ANALYZE`存储的信息的数量, 特别是给每个字段用的`most_common_vals`和`histogram_bounds`数组上的最大记录数目 可以用`ALTER TABLE SET STATISTICS`命令设置, 或者是用运行时参数[default_statistics_target](#calibre_link-979)进行全局设置。 目前缺省的限制是 100个记录。 提升该限制应该可以做出更准确的规划器估计,特别是对那些有不规则数据分布的字段而言, 代价是在`pg_statistic`里使用了更多空间,并且需要略微多一些的时间计算估计数值。相比之下, 比较低的限制可能更适合那些数据分布比较简单的字段。 有关规划器使用统计信息的进一步详情可参阅[Chapter 60](#calibre_link-1204)。