17.6. 查询规划

17.6.1. 规划器方法配置

这些配置参数提供了一个用于影响查询优化器选择的查询规划的原始的方法。 如果优化器为特定的查询选择的缺省规划并不是最优, 那么我们就可以通过使用这些配置参数强制优化器选择一个更好的规划来临时解决这个问题。 不过,永久地关闭这些设置几乎从不是个好主意。 更好的改善优化器选择的规划的方法包括调节 规划器开销常量, 更频繁运行 ANALYZE, 增大配置参数 default_statistics_target 的值, 以及使用 ALTER TABLE SET STATISTICS 为某个字段增加收集的统计信息。

enable_bitmapscan (boolean)

打开或者关闭规划器对位图扫描规划类型的使用。缺省是 on

enable_hashagg (boolean)

打开或者关闭查询规划器对散列聚集规划类型的时候。缺省是 on

enable_hashjoin (boolean)

打开或者关闭查询规划器对散列连接规划类型的使用。 缺省是 on

enable_indexscan (boolean)

打开或者关闭查询规划期对索引扫描规划类型的使用。 缺省是 on

enable_mergejoin (boolean)

打开或者关闭查询规划器对融合连接规划类型的使用。 缺省是 on

enable_nestloop (boolean)

打开或者关闭查询规划器对嵌套循环连接规划类型的使用。 我们不可能完全消除嵌套循环连接, 但是把这个变量关闭就会让规划器在存在其它方法的时候优先选择其他的。 缺省是 on

enable_seqscan (boolean)

打开或者关闭查询规划器对顺序扫描规划类型的使用。 我们不可能完全消除顺序扫描,但是把这个变量关闭会让规划器在存在其它方法的时候优先选择其它的。 缺省是 on

enable_sort (boolean)

打开或者关闭查询规划器使用明确的排序步骤。我们不可能完全消除明确的排序, 但是把这个变量关闭可以让规划器在存在其它方法的时候优先选择其它方法。 缺省是 on

enable_tidscan (boolean)

打开或者关闭查询规划器对 TID 扫描规划类型的使用。 缺省是 on

17.6.2. 规划器开销常量

注意: 糟糕的是,现在还没有定义得很合理的方法来判断下面出现的"开销"变量族的理想数值。 我们鼓励你做各种试验并分享你的发现。

effective_cache_size (floating point)

为规划器设置在一次索引扫描中可用的磁盘缓冲区的有效大小。 这个参数在计算一个索引的开销的预计值的时候会加以考虑; 一个更高的数值会导致很可能使用索引扫描,数值低了会更有可能选择顺序扫描。 在设置这个参数的时候,你还应该考虑 PostgreSQL 的数据文件会使用的的共享缓冲区和内核的磁盘缓冲。 还有,还要考虑预计会有的使用不同索引的并发查询数目, 因为它们必须共享可用的内存空间。这个参数对 PostgreSQL 分配的共享内存大小没有影响, 它也不会使用内核磁盘缓冲;它只用于估算。数值是用磁盘页来计算的, 通常每个页面是 8192 字节。缺省是 1000。

random_page_cost (floating point)

设置规划器计算的一次非顺序磁盘页面抓取的开销。 这是以顺序磁盘页面抓取的开销的倍数计量的。 更高的数值令优化器更倾向于选择一次顺序扫描,低数值的时候则倾向于使用索引扫描。 缺省是四。

cpu_tuple_cost (floating point)

设置规划器预计在一次查询中处理一个数据行的开销。 这是以一次顺序页面抓取的开销的分数来计量的。 缺省是 0.01。

cpu_index_tuple_cost (floating point)

设置在一次索引扫描中规划器计算出来的处理每条索引行的开销。 这是以一次顺序页面抓取的开销的分数来计量的。缺省是 0.001。

cpu_operator_cost (floating point)

设置规划器计算出来的处理一条WHERE子句中的每个操作符的开销。 这是以一次顺序页面抓取的开销的分数来计量的。缺省是 0.0025。

17.6.3. 基因查询优化器

geqo (boolean)

允许或禁止基因查询优化,这是一种试图不通过穷举搜索来实现查询规划的算法。缺省是允许。 geqo_threshold 变量提供了一种为特定类别的查询关闭 GEQO 的粒度更好的方法。

geqo_threshold (integer)

只有当涉及的FROM关系数量至少有这么多个的时候,才使用基因查询优化。 (请注意一个外JOIN构造只算做一个FROM项。) 缺省是 12,对于数量小于此数的查询,也许使用判定性的穷举搜索更有效。 但是对于有许多表的查询,规划器做判断要花很多时间。

geqo_effort (integer)

控制 GEQO 里规划时间和查询规划的有效性之间的平衡。 这个变量必须事一个范围从 1 到 10 的整数。缺省值是 5。 大的数值增加花在进行查询规划上面的时间,但是也很可能会提高选中更有效的查询规划的几率。

geqo_effort 实际上并没有直接干什么事情; 只是用于计算其它那些影响 GEQO 行为的变量的缺省值(在下面描述)。 如果你愿意,你可以手工设置其它参数。

geqo_pool_size (integer)

控制 GEQ0 使用的池大小。池大小是一个全体中的个体的数量。 它必须至少是二,并且有用的数值通常在 100 和 1000 之间。 如果把它设置为零(缺省设置),那么就会基于 geqo_effort 和查询中表的数量选取一个合适的缺省。

geqo_generations (integer)

控制 GEQO 使用的子代的数目。子代声明算法的迭代的数目。 它必须至少是一,有用的值范围和池的大小相同。如果设置为零(缺省),那么将基于 geqo_pool_size 选取合适的缺省。

geqo_selection_bias (floating point)

控制 GEQO 使用的选择性偏好。选择性偏好是在一个种群中的选择性压力。 数值可以是 1.5 到 2.0 之间;后者是缺省。

17.6.4. 其它规划器选项

default_statistics_target (integer)

为没有用 ALTER TABLE SET STATISTICS 设置字段相关目标的表中其它字段设置缺省统计目标。 更大的数值增加了 ANALYZE 所需要的时间,但是可能会改善规划器的估计质量。缺省值是 10。 有关 PostgreSQL 的查询规划器使用的统计的更多信息,请参考 Section 13.2

constraint_exclusion (boolean)

打开或者关闭查询规划器使用表约束限制表访问的特性。缺省是off

如果这个参数是 on,那么规划器用查询条件和 CHECK 约束进行比较, 并且在条件和约束冲突的情况下,忽略对表的扫描。(目前,在继承扫描的时候,这些事情只是为子表进行处理。) 比如:

CREATE TABLE parent(key integer, ...);
CREATE TABLE child1000(check (key between 1000 and 1999)) INHERITS(parent);
CREATE TABLE child2000(check (key between 2000 and 2999)) INHERITS(parent);
...
SELECT * FROM parent WHERE key = 2400;

在打开约束排除的时候,这个 SELECT 将完全不会扫描 child1000。 这样可以在使用继承制作分区表的时候提高性能。

目前,constraint_exclusion 缺省是 off, 因为如果查询规划被缓冲了,那么就会有不正确的结果的风险 — 如果一个表约束改变或者删除了, 那么前面生成的查询计划现在就可能是错的了,而又没有内置的机制强制重新规划。 (这个缺点可能会在将来的 PostgreSQL 版本得到修改。) 另外一个把它关闭的原因是约束检查相对来说开销还是比较大的, 在很多环境下它并不能节约开销。只是在你实际上使用了从设计上就利用这个特性的优点的表分区的场合下, 我们才推荐打开它。

参考 Section 5.9 获取有关使用约束排除和分区的更多信息。

from_collapse_limit (integer)

如果生成的 FROM 列表不超过这个限制的项数,规划器将把子查询融合到上层查询。 小的数值降低规划的时间,但是可能会生成差些的查询计划。 缺省是 8。通常,把它限制在小于 geqo_threshold 的数值是比较明智的。

join_collapse_limit (integer)

如果得出的列表不超过这个数目的项,那么规划器将把明确的内 JOIN 构造抹平到 FROM 列表项中。 PostgreSQL 7.4 以前,通过 JOIN 构造声明的连接绝对不会被查询规划期重排。 现在的查询规划器已经改进过了,这样,用这种形式写出来的内层连接就可以重排了; 这个配置参数控制这种重排的程度。

注意: 目前,用 JOIN 构造声明的外联接的顺序从来不会查询规划器被调整; 因此,join_collapse_limit 在这个行为上没有效果。 在未来的 PostgreSQL 版本里,规划器可能会改进某些外联接类型的重排。

缺省时,这个值设置为和 from_collapse_limit 相同, 这个值适合大多数场合。把它设置为 1 则避免任何内 JOIN 的融合,就可以使用明确的 JOIN 语法来控制连接顺序。查询优化器并不是总能选取最优的联接顺序;高级用户可以选择暂时把这个变量设置为 1, 然后明确地声明他们需要的联接顺序。把这个变量设置为 1 的另外一个后果是查询规划器会表现得更像 PostgreSQL 7.3 查询规划器,可能对一些用户做向下兼容很有用。

把这个数值设置为 1 和 from_collapse_limit 之间可能对于在规划时间和选取的规划的质量之间有个平衡 (越高的数值生成越好的规划)。