19.7. 查询计划

19 .7.1. 规划器方法配置

这些配置参数提供了一种影响查询优化器选择的查询计划的粗略方法。如果优化器为特定查询选择的默认计划不是最佳选择,那么临时解决方案是使用这些配置参数之一来强制优化器选择其他计划。改善优化程序选择的计划质量的更好方法包括调整计划程序成本常量(请参见Section 19.7.2),手动运行ANALYZE,增加default_statistics_target配置参数的值以及使用ALTER TABLE SET STATISTICS增加针对特定列收集的统计信息量。

  • enable_bitmapscan ( boolean )

    • 启用或禁用查询计划程序对位图扫描计划类型的使用。默认值为on
  • enable_gathermerge ( boolean )

    • 启用或禁用查询计划程序对收集合并计划类型的使用。默认值为on
  • enable_hashagg ( boolean )

    • 启用或禁用查询计划程序对哈希聚合计划类型的使用。默认值为on
  • enable_hashjoin ( boolean )

    • 启用或禁用查询计划程序对哈希联接计划类型的使用。默认值为on
  • enable_indexscan ( boolean )

    • 启用或禁用查询计划者对索引扫描计划类型的使用。默认值为on
  • enable_indexonlyscan ( boolean )

    • 启用或禁用查询计划程序对仅索引扫描计划类型的使用(请参阅Section 11.9)。默认值为on
  • enable_material ( boolean )

    • 启用或禁用查询计划程序对实现的使用。不可能完全抑制实现,但是关闭此变量将阻止计划者插入实现节点,除非需要正确性的情况。默认值为on
  • enable_mergejoin ( boolean )

    • 启用或禁用查询计划程序对合并联接计划类型的使用。默认值为on
  • enable_nestloop ( boolean )

    • 启用或禁用查询计划程序对嵌套循环联接计划的使用。不可能完全抑制嵌套循环联接,但是如果有其他可用方法,则关闭此变量将阻止计划者使用一个。默认值为on
  • enable_parallel_append ( boolean )

    • 启用或禁用查询计划程序对并行感知的追加计划类型的使用。默认值为on
  • enable_parallel_hash ( boolean )

    • 启用或禁用查询计划程序对带有并行哈希的哈希联接计划类型的使用。如果未同时启用哈希联接计划,则无效。默认值为on
  • enable_partition_pruning ( boolean )

    • 启用或禁用查询计划程序从查询计划中删除分区表分区的功能。这也控制了计划者生成查询计划的能力,该能力使查询执行者可以在查询执行期间删除(忽略)分区。默认值为on。有关详情,请参见Section 5.10.4
  • enable_partitionwise_join ( boolean )

    • 启用或禁用查询计划程序对按分区联接的使用,这允许通过联接匹配的分区来执行分区表之间的联接。当前,按分区联接仅在联接条件包括所有分区键时才适用,这些键必须具有相同的数据类型并且具有完全匹配的子分区集。由于按分区分区联接计划在计划期间会占用大量 CPU 时间和内存,因此默认值为off
  • enable_partitionwise_aggregate ( boolean )

    • 启用或禁用查询计划程序对分区分组或聚合的使用,这允许对每个分区分别执行的分区表进行分组或聚合。如果GROUP BY子句不包含分区键,则只能在每个分区的基础上执行部分聚合,并且必须稍后执行终结处理。由于按分区分组或聚合可能在计划期间占用大量 CPU 时间和内存,因此默认值为off
  • enable_seqscan ( boolean )

    • 启用或禁用查询计划程序对 Sequences 扫描计划类型的使用。不可能完全抑制 Sequences 扫描,但是如果有其他可用方法,则关闭此变量将阻止计划者使用一种。默认值为on
  • enable_sort ( boolean )

    • 启用或禁用查询计划程序对显式排序步骤的使用。不可能完全抑制显式排序,但是如果有其他可用方法,则关闭此变量将阻止计划者使用一种。默认值为on
  • enable_tidscan ( boolean )

    • 启用或禁用查询计划者对 TID 扫描计划类型的使用。默认值为on

19 .7.2. 计划者成本常数

本节中描述的* cost *变量以任意比例进行度量。只有它们的相对值很重要,因此将它们全部按相同的系数上下缩放将不会导致计划者的选择发生变化。默认情况下,这些成本变量基于 Sequences 页面获取的成本;也就是说,通常将seq_page_cost设置为1.0,其他成本变量则以此为基准进行设置。但是您可以根据需要使用不同的比例,例如特定机器上的实际执行时间(以毫秒为单位)。

Note

不幸的是,没有确定成本变量理想值的明确方法。最好将它们视为特定安装将接收的整个查询组合的平均值。这意味着仅根据几个实验进行更改是非常危险的。

  • seq_page_cost ( floating point )

    • 设置计划程序对磁盘页读取成本的估算,该开销是一系列 Sequences 读取的一部分。默认值为 1.0. 通过设置相同名称的表空间参数(请参见ALTER TABLESPACE),可以为特定表空间中的表和索引覆盖此值。
  • random_page_cost ( floating point )

    • 设置计划者对非连续获取的磁盘页面的成本的估计。默认值为 4.0. 通过设置相同名称的表空间参数(请参见ALTER TABLESPACE),可以为特定表空间中的表和索引覆盖此值。

相对于seq_page_cost减小此值将导致系统更喜欢索引扫描;提高它会使索引扫描看起来相对更昂贵。您可以一起提高或降低这两个值,以更改磁盘 I/O 成本相对于 CPU 成本的重要性,这由以下参数描述。

对机械磁盘存储的随机访问通常比 Sequences 访问的四倍昂贵。但是,使用较低的默认值(4.0),因为假定对磁盘的大多数随机访问(如索引读取)位于缓存中。可以将默认值认为是对随机访问进行建模的速度比 Sequences 慢 40 倍,同时预计 90%的随机读取将被缓存。

如果您认为 90%的缓存速率是对工作负载的错误假设,则可以增加 random_page_cost 以更好地反映随机存储读取的真实成本。相应地,如果您的数据有可能完全位于缓存中(例如,当数据库小于服务器总内存时),则减少 random_page_cost 可能是适当的。相对于 Sequences 存储的随机读取成本较低的存储,例如固态驱动器,也可以通过对 random_page_cost 较低的值进行更好的建模。

Tip

尽管系统允许您将random_page_cost设置为小于seq_page_cost,但是这样做并不实际。但是,如果将数据库完全缓存在 RAM 中,则将它们设置为相等是有意义的,因为在这种情况下,按 Sequences 触摸页面不会造成任何损失。同样,在高速缓存的数据库中,您应该降低两个值,相对于 CPU 参数,这是因为获取 RAM 中已经存在的页面的成本比通常要小得多。

  • cpu_tuple_cost ( floating point )

    • 设置计划者对查询期间每行处理成本的估计。默认值为 0.01.
  • cpu_index_tuple_cost ( floating point )

    • 设置计划程序对索引扫描期间处理每个索引条目的成本的估计。默认值为 0.005.
  • cpu_operator_cost ( floating point )

    • 设置计划者对查询期间执行的每个运算符或函数的处理成本的估计。默认值为 0.0025.
  • parallel_setup_cost ( floating point )

    • 设置计划者对启动并行工作进程的成本的估计。默认值为 1000.
  • parallel_tuple_cost ( floating point )

    • 设置计划者对将一个 Tuples 从并行工作进程转移到另一进程的成本的估计。默认值为 0.1.
  • min_parallel_table_scan_size ( integer )

    • 设置为了考虑并行扫描而必须扫描的最小表数据量。对于并行 Sequences 扫描,扫描的表数据量始终等于表的大小,但是当使用索引时,扫描的表数据量通常会更少。默认值为 8 兆字节(8MB)。
  • min_parallel_index_scan_size ( integer )

    • 设置为了考虑并行扫描而必须扫描的最小索引数据量。请注意,并行索引扫描通常不会涉及整个索引。计划程序认为相关扫描实际上会触及的页数。默认值为 512 KB(512kB)。
  • effective_cache_size ( integer )

    • 设置计划者对单个查询可用的磁盘缓存有效大小的假设。这是使用索引的成本估算中的因素;值越高,越有可能使用索引扫描;值越低,越有可能使用 Sequences 扫描。设置此参数时,您应该同时考虑 PostgreSQL 的共享缓冲区和将用于 PostgreSQL 数据文件的内核磁盘缓存部分,尽管这两个地方可能都存在一些数据。另外,请考虑不同表上的并发查询的预期数量,因为它们将必须共享可用空间。该参数对 PostgreSQL 分配的共享内存的大小没有影响,也不会保留内核磁盘缓存;它仅用于估计目的。系统也不假定查询之间的数据保留在磁盘缓存中。默认值为 4 GB(4GB)。
  • jit_above_cost ( floating point )

    • 设置查询成本,如果启用该查询成本,则会在该成本之上激活 JIT 编译(请参见Chapter 32)。执行 JIT 会花费计划时间,但可以加快查询执行速度。将此设置为-1将禁用 JIT 编译。默认值为100000
  • jit_inline_above_cost ( floating point )

    • 设置查询成本,高于该成本时,JIT 编译将尝试内联函数和运算符。内联会增加计划时间,但可以提高执行速度。将此值设置为小于jit_above_cost是没有意义的。将此设置为-1将禁用内联。默认值为500000
  • jit_optimize_above_cost ( floating point )

    • 设置查询成本,超过此成本 JIT 编译将应用昂贵的优化。这种优化会增加计划时间,但可以提高执行速度。将其设置为小于jit_above_cost是没有意义的,并且将其设置为大于jit_inline_above_cost不太可能是有益的。将此设置为-1将禁用昂贵的优化。默认值为500000

19 .7.3. 遗传查询优化器

遗传查询优化器(GEQO)是一种使用启发式搜索进行查询计划的算法。这样可以减少复杂查询(那些包含许多关系的查询)的计划时间,但所产生的计划有时会比通常的穷举搜索算法所发现的计划差。有关更多信息,请参见Chapter 60

  • geqo ( boolean )

    • 启用或禁用遗传查询优化。默认情况下处于启用状态。通常最好不要在 Producing 关闭它。 geqo_threshold变量可提供对 GEQO 的更精细控制。
  • geqo_threshold ( integer )

    • 使用遗传查询优化来计划涉及至少FROM项的查询。 (请注意,一个FULL OUTER JOIN构造仅计入一个FROM项.)默认值为 12.对于更简单的查询,通常最好使用常规的穷举搜索计划程序,但是对于具有多个表的查询,穷举搜索会花费太长时间,通常比执行次优计划的代价更长。因此,查询大小的阈值是 ManagementGEQO 使用的便捷方法。
  • geqo_effort ( integer )

    • 在 GEQO 中控制计划时间和查询计划质量之间的权衡。此变量必须是 1 到 10 之间的整数。默认值为 5.较大的值会增加执行查询计划所花费的时间,但也会增加选择有效查询计划的可能性。

geqo_effort实际上并没有直接做任何事情;它仅用于计算影响 GEQO 行为的其他变量的默认值(如下所述)。如果愿意,您可以手动设置其他参数。

  • geqo_pool_size ( integer )

    • 控制 GEQO 使用的池大小,即遗传种群中的个体数量。它必须至少为两个,有用的值通常为 100 到 1000.如果将其设置为零(默认设置),则根据geqo_effort和查询中的表数选择合适的值。
  • geqo_generations ( integer )

    • 控制 GEQO 使用的世代数,即算法的迭代数。它必须至少为 1,并且有用的值与池大小在同一范围内。如果将其设置为零(默认设置),则根据geqo_pool_size选择合适的值。
  • geqo_selection_bias ( floating point )

    • 控制 GEQO 使用的选择偏差。选择偏差是总体内部的选择压力。值可以在 1.50 到 2.00 之间;后者是默认设置。
  • geqo_seed ( floating point )

    • 控制 GEQO 使用的随机数生成器的初始值,以选择通过连接 Sequences 搜索空间的随机路径。该值的范围可以从零(默认)到一。改变值将更改探索的连接路径集,并可能导致找到更好或更差的最佳路径。

19 .7.4. 其他计划者选项

  • default_statistics_target ( integer )

    • 为没有通过ALTER TABLE SET STATISTICS设置特定于列的目标的表列设置默认统计信息目标。较大的值会增加ANALYZE所需的时间,但可能会提高计划者估算的质量。缺省值为 100.有关 PostgreSQL 查询计划程序使用统计信息的更多信息,请参见Section 14.2
  • constraint_exclusion ( enum )

    • 控制查询计划者对表约束的使用以优化查询。 constraint_exclusion的允许值为on(检查所有表的约束),off(从不检查约束)和partition(仅检查继承子表和UNION ALL子查询的约束)。 partition是默认设置。它通常与传统继承树一起使用以提高性能。

当此参数允许它用于特定表时,计划者将查询条件与表的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,从而提高了性能。

当前,默认情况下仅在经常用于通过继承树实现表分区的情况下启用约束排除。在所有表上都打开它会带来额外的计划开销,这在简单查询中非常明显,大多数情况下,对于简单查询不会产生任何好处。如果没有使用传统继承进行分区的表,则可能希望完全将其关闭。 (请注意,分区表的等效功能由一个单独的参数enable_partition_pruning控制。)

有关使用约束排除来实现分区的更多信息,请参考Section 5.10.5

  • cursor_tuple_fraction ( floating point )

    • 设置计划者对将要检索的游标行的分数的估计。默认值为 0.1. 此设置的较小值会使计划者偏向于对游标使用“快速启动”计划,这将快速检索前几行,而可能需要很长时间才能获取所有行。较大的值将更多的重点放在总的估计时间上。在最大设置为 1.0 的情况下,游标的计划与常规查询完全一样,仅考虑估计的总时间,而不考虑第一行的交付时间。
  • from_collapse_limit ( integer )

    • 如果生成的FROM列表所包含的项目不多,则计划者会将子查询合并到较高的查询中。较小的值会减少计划时间,但可能会产生劣等的查询计划。默认值为八。有关更多信息,请参见Section 14.3

将此值设置为geqo_threshold或更大可能会触发使用 GEQO 计划程序,从而导致计划不理想。参见Section 19.7.3

  • jit ( boolean )

    • 确定 PostgreSQL 是否可以使用 JIT 编译(如果可用)(请参见Chapter 32)。默认值为off
  • join_collapse_limit ( integer )

    • 每当产生不超过这么多项目的列表时,计划者就会将明确的JOIN构造(FULL JOIN除外)重写为FROM项目的列表。较小的值会减少计划时间,但可能会产生劣等的查询计划。

默认情况下,此变量的设置与from_collapse_limit相同,适用于大多数用途。将其设置为 1 可防止对显式JOIN进行任何重新排序。因此,查询中指定的显式连接 Sequences 将是关系之间的实际连接 Sequences。由于查询计划者并不总是选择最佳的连接 Sequences,因此高级用户可以选择将该变量临时设置为 1,然后明确指定他们想要的连接 Sequences。有关更多信息,请参见Section 14.3

将此值设置为geqo_threshold或更大可能会触发使用 GEQO 计划程序,从而导致计划不理想。参见Section 19.7.3

  • parallel_leader_participation ( boolean )

    • 允许领导者进程在GatherGather Merge节点下执行查询计划,而不是 await 工作进程。默认值为on。将此值设置为off可以减少由于领导者没有足够快地读取 Tuples 而导致工作程序被阻塞的可能性,但是要求领导程序进程 await 工作程序启动才能生成第一个 Tuples。领导者可以帮助或阻碍绩效的程度取决于计划类型,工作人员数量和查询持续时间。
  • force_parallel_mode ( enum )

    • 允许将并行查询用于测试目的,即使在预期不会带来性能收益的情况下也是如此。 force_parallel_mode的允许值为off(仅在期望提高性能时才使用并行模式),on(对认为安全的所有查询强制使用并行查询)和regress(与on类似,但具有其他行为更改)如下所述)。

更具体地说,将此值设置为on会将Gather节点添加到看起来安全的任何查询计划的顶部,以便查询在并行工作程序内部运行。即使当并行工作器不可用或无法使用时,除非计划者认为这将导致查询失败,否则将禁止诸如在并行查询上下文中禁止启动子事务之类的操作。如果设置此选项时发生故障或意外结果,则查询中使用的某些功能可能需要标记为PARALLEL UNSAFE(或者可能是PARALLEL RESTRICTED)。

将此值设置为regress具有与将其设置为on相同的所有效果,以及一些旨在促进自动回归测试的其他效果。通常,来自并行工作程序的消息包括上下文行,指示该行,但是设置regress会禁止该行,因此输出与非并行执行中的输出相同。同样,通过此设置添加到计划中的Gather节点隐藏在EXPLAIN输出中,以便输出与如果将此设置设为off所获得的结果匹配。