9.3 9.4 9.5 9.6 10 11 12 13 14 15 16 17 Current(18)
PostgreSQL中文社区 问题报告 纠错本页面

19.7. 查询规划 #

19.7.1. 规划器方法配置
19.7.2. 规划器代价常量
19.7.3. 遗传查询优化器
19.7.4. 其他规划器选项

19.7.1. 规划器方法配置 #

这些配置参数提供了影响查询优化器选择查询计划的粗略方法。 如果优化器为特定的查询选择的默认计划不是最优的,一种临时解决方案是使用这些配置参数之一来强制优化器选择一个不同的计划。 提高优化器选择的计划质量的更好的方式包括调整规划器的代价常数(见第 19.7.2 节)、手工运行ANALYZE、增加default_statistics_target配置参数的值,以及使用ALTER TABLE SET STATISTICS增加为特定列收集的统计信息量。

enable_async_append (boolean) #

激活或禁用查询计划对异步感知附加计划类型的使用。默认为on

enable_bitmapscan (boolean) #

允许或禁止查询规划器使用位图扫描计划类型。默认值是on

enable_distinct_reordering (boolean) #

启用或禁用查询规划器重新排序 DISTINCT 键以匹配输入路径的 pathkeys 的能力。默认值为 on

enable_gathermerge (boolean) #

启用或禁用查询规划器对收集归并计划类型的使用。默认值是on

enable_group_by_reordering (boolean) #

控制查询规划器是否生成一个计划,该计划将提供 GROUP BY 键按计划中子节点(例如索引扫描)的键顺序排序。 当禁用时,查询规划器将生成一个计划,其 GROUP BY 键仅按 ORDER BY 子句排序(如果有)。 启用时,规划器将尝试生成更高效的计划。默认值为 on

enable_hashagg (boolean) #

允许或禁用查询规划器使用哈希聚合计划类型。默认值是on

enable_hashjoin (boolean) #

允许或禁用查询规划器使用哈希连接计划类型。默认值是on

enable_incremental_sort (boolean) #

启用或禁用查询规划器对增量排序步骤的使用。默认值是on

enable_indexscan (boolean) #

启用或禁用查询规划器使用索引扫描和仅索引扫描计划类型。 默认值是on。另请参见 enable_indexonlyscan

enable_indexonlyscan (boolean) #

启用或禁用查询规划器使用仅索引扫描计划类型(请参阅 第 11.9 节)。默认值为 onenable_indexscan设置 也必须启用,以使查询规划器考虑仅索引扫描。

enable_material (boolean) #

启用或禁用查询规划器使用物化。它不可能完全禁用物化, 但是关闭这个变量将阻止规划器插入物化节点,除非为了保证 正确性。默认值是on

enable_memoize (boolean) #

启用或禁用查询规划器对memoize计划的使用,以便缓存在 嵌套循环连接中参数化扫描的结果。在当前参数的结果已经 在缓存中时,此计划类型允许跳过对底层计划的扫描。当新 条目需要更多空间时,不太常用的查询结果可能会从缓存中 去除。默认值是on

enable_mergejoin (boolean) #

启用或禁用查询规划器使用归并连接计划类型。默认值是on

enable_nestloop (boolean) #

允许或禁止查询规划器使用嵌套循环连接计划。它不可能完全禁止嵌套循环连接,但是关闭这个变量将使得规划器尽量不使用嵌套循环连接,如果有其他方法可用。默认值是on

enable_parallel_append (boolean) #

允许或禁止查询规划器使用并行追加计划类型。默认值是on

enable_parallel_hash (boolean) #

允许或禁止查询规划器对并行哈希使用哈希连接计划类型。如果哈希连接计划也没有启用,这个参数没有效果。默认值是on

enable_partition_pruning (boolean) #

允许或禁止查询规划器从查询计划中消除一个分区表的分区。这也控制着规划器产生允许查询执行器在查询执行期间移除(忽略)分区的查询计划的能力。默认值是on。详情请参考第 5.12.4 节

enable_partitionwise_join (boolean) #

启用或禁用查询规划器对分区连接的使用,这允许通过连接匹配的分区来 执行分区表之间的连接。目前,分区连接仅适用于连接条件包括所有分区 键的情况,这些分区键必须具有相同的数据类型,并且具有一对一匹配的 子分区集。启用此设置后,最终计划中受work_mem 限制内存使用的节点数量可能会根据扫描的分区数量线性增加。这可能导 致查询执行期间整体内存消耗的大幅增加。查询规划在内存和CPU方面也会 变得显著更昂贵。默认值为off

enable_partitionwise_aggregate (boolean) #

启用或禁用查询规划器对分区分组或聚合的使用,这允许对分区表的分组或聚合 可以分别针对每个分区执行。如果GROUP BY子句不包括分区键, 则只能在每个分区的基础上执行部分聚合,最终的聚合必须稍后完成。启用此设置 后,最终计划中受work_mem限制的节点数量可能会根据扫描的 分区数量线性增加。这可能导致查询执行期间整体内存消耗大幅增加。查询规划在 内存和CPU方面也会变得显著更昂贵。默认值为off

enable_presorted_aggregate (boolean) #

控制查询规划器是否会生成一个计划,该计划将提供按查询所需顺序 预排序的行,用于ORDER BY / DISTINCT 聚合函数。当禁用时,查询规划器将生成一个计划,该计划始终要求 执行器在对每个包含ORDER BYDISTINCT 子句的聚合函数进行聚合之前执行排序。启用时,规划器将尝试生成 一个更高效的计划,该计划为聚合函数提供按其聚合所需顺序预排序的 输入。默认值是on

enable_self_join_elimination (boolean) #

启用或禁用查询规划器的优化,该优化分析查询树并用 语义上等效的单次扫描替换自连接。仅考虑普通表。 默认值为on

enable_seqscan (boolean) #

允许或禁止查询规划器使用顺序扫描计划类型。它不可能完全禁止顺序扫描,但是关闭这个变量将使得规划器尽可能优先使用其他方法。默认值是on

enable_sort (boolean) #

允许或禁止查询规划器使用显式排序步骤。它不可能完全禁止显式排序,但是关闭这个变量将使得规划器尽可能优先使用其他方法。默认值是on

enable_tidscan (boolean) #

允许或禁止查询规划器使用TID扫描计划类型。默认值是on

19.7.2. 规划器代价常量 #

这一节中描述的代价变量可以按照任意尺度衡量。我们只关心它们的相对值,将它们以相同的因子缩放不会影响规划器的选择。默认情况下,这些代价变量是基于顺序页面获取的代价的,即seq_page_cost被设置为1.0并且其他代价变量都参考它来设置。不过你可以使用你喜欢的不同尺度,例如在一个特定机器上的真实执行时间。

注意

不幸的是,没有一种良好定义的方法来决定代价变量的理想值。它们最好被作为一个特定安装将接收到的查询的平均值来对待。这意味着基于少量的实验来改变它们是有风险的。

seq_page_cost (floating point) #

设置规划器对一系列顺序磁盘页面获取中的一次的代价估计。默认值是 1.0。通过设置同名的表空间参数,这个值可以重写为一个特定的表空间(见ALTER TABLESPACE)。

random_page_cost (floating point) #

设置规划器对一次非顺序获取磁盘页面的代价估计。默认值是 4.0。通过设置同名的表空间参数,这个值可以重写为一个特定的表空间(见ALTER TABLESPACE)。

减少这个值(相对于seq_page_cost)将导致系统更倾向于索引扫描;提高它将让索引扫描看起来相对更昂贵。你可以一起提高或降低两个值来改变磁盘 I/O 代价相对于 CPU 代价的重要性,后者由下列参数描述。

对持久存储的随机访问通常比顺序访问贵四倍以上。 但是,使用较低的默认值(4.0),因为大多数对存储的随机访问,如索引读取,被认为是在缓存中。此外,网络附加存储的延迟往往会降低随机访问的相对开销。

如果您认为缓存的频率低于默认值所反映的情况,并且网络延迟很小,您可以增加 random_page_cost 以更好地反映随机存储读取的真实成本。相对于顺序读取,具有更高随机读取成本的存储,如磁盘,可能也更适合用更高的 random_page_cost 值建模。相应地,如果您的数据可能完全在缓存中,例如当数据库小于总服务器内存时,或者网络延迟很高,降低 random_page_cost 可能是合适的。

提示

虽然系统允许你将random_page_cost设置得小于seq_page_cost,但这样做在物理上并不合理。然而,当数据库完全缓存于 RAM 中时,将它们设置为相等是有意义的,因为在这种情况下,乱序访问页面并不会带来额外的开销。同样,在一个高度缓存的数据库中,你应该相对于 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) #

设置规划器对于从一个并行工作进程传递一个元组给另一个进程的代价估计。默认是 0.1。

min_parallel_table_scan_size (integer) #

设置必须扫描的表数据的最小量,以便考虑使用并行扫描。对于并行顺序扫描,被扫描的表数据量总是等于表的大小,但在使用索引时,被扫描的表数据量通常会更少。 如果指定值时没有单位,则以块为单位,即BLCKSZ字节,通常为8kB。默认值是8兆字节(8MB)。

min_parallel_index_scan_size (integer) #

设置必须扫描的索引数据的最小量,以便考虑使用并行扫描。注意并行索引扫描通常不会触及整个索引;它是规划器认为该扫描会实际用到的相关页面的数量。这个参数还用于决定特定的索引是否参与并行清理。参见VACUUM。 如果指定值时没有单位,则以块为单位,即BLCKSZ字节,通常为8kB。默认值是512千字节(512kB)。

effective_cache_size (integer) #

设置规划器对一个单一查询可用的有效磁盘缓存大小的假设。这个参数会被考虑在使用索引的代价估计中;更高的数值会使得索引扫描更可能被使用,更低的数值会使得顺序扫描更可能被使用。在设置这个参数时,你还应该考虑PostgreSQL的共享缓冲区以及将被用于PostgreSQL数据文件的内核磁盘缓存,尽管有些数据可能在两个地方都存在。还要考虑预计在不同表上的并发查询数量,因为它们必须共享可用的空间。这个参数对PostgreSQL分配的共享内存大小没有影响,也不会保留内核磁盘缓存;它只用于估计目的。系统也不会假设在查询之间数据会保留在磁盘缓存中。如果指定值时没有单位,则以块为单位,即BLCKSZ字节,通常为8kB。默认值是4吉字节(4GB)。(如果BLCKSZ不是8kB,默认值会按比例缩放。)

jit_above_cost (floating point) #

设置激活JIT编译的查询代价,如果查询代价超过这个值就会激活JIT编译(如果启用了JIT,见第 30 章)。执行JIT会消耗一些规划时间,但是能够加速查询执行。将这个值设置为-1会禁用JIT编译。默认值是100000

jit_inline_above_cost (floating point) #

设置JIT编译尝试内联函数和操作符的查询代价阈值,如果查询代价超过这个值,JIT编译就会尝试内联。内联会增加规划时间,但是可以提高执行速度。将这个参数设置成小于jit_above_cost是没有意义的。将这个参数设置为-1会禁用内联。默认值是500000

jit_optimize_above_cost (floating point) #

设置JIT编译应用优化的查询代价阈值,如果查询代价超过这个值,JIT编译就会应用开销较大的优化。这类优化会增加规划时间,但是更能够改进执行速度。将这个参数设置成小于jit_above_cost是没有意义的,并且将它设置成大于jit_inline_above_cost也未必有益。将这个参数设置为-1会禁用开销较大的优化。默认值是500000

19.7.3. 遗传查询优化器 #

遗传查询优化器(GEQO)是一种使用启发式搜索来进行查询规划的算法。它可以降低对于复杂查询(连接很多表的查询)的规划时间,但是代价是它产生的计划有时候要差于使用穷举搜索算法找到的计划。详见第 61 章

geqo (boolean) #

允许或禁止遗传查询优化。默认是启用。在生产环境中通常最好不要关闭它。geqo_threshold变量提供了对 GEQO 更细粒度的控制。

geqo_threshold (integer) #

只有当涉及的FROM项数量至少有这么多个的时候,才使用遗传查询优化(注意一个FULL OUTER JOIN只被计为一个FROM项)。默认值是 12。对于更简单的查询,通常会使用普通的穷举搜索规划器,但是对于有很多表的查询穷举搜索会花很长时间,通常比执行一个次优的计划带来的惩罚值还要长。因此,在查询大小上的一个阈值是管理 GEQO 使用的一种方便的方法。

geqo_effort (integer) #

控制 GEQO 中规划时间和查询计划质量之间的折中。这个变量必须是位于 1 到 10 之间的一个整数。默认值是 5。更大的值会增加花在查询规划上的时间,但是同时也增加了选择一个高效查询计划的可能性。

geqo_effort实际并不直接做任何事情;它只是被用来计算其他影响 GEQO 行为的变量(如下所述)的默认值。如果你愿意,你可以手工设置其他参数。

geqo_pool_size (integer) #

控制 GEQO 使用的池尺寸,它就是遗传种群中的个体数目。它必须至少为 2,且有用的值通常在 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 使用的随机数生成器的初始值,随机数生成器用于在连接顺序搜索空间中选择随机路径。该值可以从 0 (默认值)到 1。变化该值会改变被探索的连接路径集合,并且可能导致找到一个更好或更差的路径。

19.7.4. 其他规划器选项 #

default_statistics_target (integer) #

为没有通过ALTER TABLE SET STATISTICS设置列相关目标的表列设置默认统计目标。更大的值增加了需要做ANALYZE的时间,但可能会改善规划器的估计质量。默认值是100。有关PostgreSQL查询规划器使用的统计信息的更多内容,请参考第 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.)

更多关于使用约束排除实现分区的信息请参阅第 5.12.5 节

cursor_tuple_fraction (floating point) #

设置规划器对将被检索的一个游标的行的比例的估计。默认值是 0.1。更小的值使得规划器偏向为游标使用快速开始计划,它将很快地检索前几行但是可能需要很长时间来获取所有行。更大的值强调总的估计时间。最大设置为 1.0,游标将和普通查询完全一样地被规划,只考虑总估计时间并且不考虑前几行会被多快地返回。

from_collapse_limit (integer) #

规划器将把子查询融合到上层查询中,如果生成的FROM列表不超过这么多项。较小的值可以减少规划时间,但是可能会生成较差的查询计划。默认值是 8。详见第 14.3 节

将这个值设置为geqo_threshold或更大,可能触发使用 GEQO 规划器,从而产生非最优计划。见第 19.7.3 节

jit (boolean) #

决定如果可用(见第 30 章),PostgreSQL是否可以使用JIT编译。默认值是on

join_collapse_limit (integer) #

规划器将把显式JOIN(除了FULL JOIN)结构重写为不超过这么多项的FROM项列表。较小的值可减少规划时间,但是可能会生成较差的查询计划。

默认情况下,这个变量被设置成和from_collapse_limit相同,这样适合大多数使用。把它设置为1可避免任何显式JOIN的重排序。因此查询中指定的显式连接顺序就是关系被连接的实际顺序。因为查询规划器并不是总能选取最优的连接顺序,高级用户可以选择暂时把这个变量设置为1,然后显式地指定他们想要的连接顺序。更多信息请见第 14.3 节

将这个值设置为geqo_threshold或更大,可能触发使用GEQO规划器,从而产生非最优计划。见第 19.7.3 节

plan_cache_mode (enum) #

准备语句(显式准备或隐式生成的,例如PL/pgSQL)可以使用自定义或通用计划执行。 使用其特定的参数值集为每个执行重新生成自定义计划,而通用计划不依赖于参数值,并且可以在执行中重复使用。 因此,使用通用计划可以节省计划时间,但如果理想计划严重依赖参数值,则通用计划可能效率低下。 这些选项之间的选择通常是自动进行的,但可以通过plan_cache_mode覆盖它。 允许的值为auto(默认的)、force_custom_planforce_generic_plan。 这个设置是在执行缓存计划时考虑,而不是在准备计划时考虑。 更多信息请参阅PREPARE

recursive_worktable_factor (floating point) #

设置规划器对递归查询 的工作表的平均大小的估计值,作为查询初始非递归项的估计大小的倍数。 这有助于规划器选择将工作表与查询的其他表连接的最合适方法。 默认值为10.0。当递归从一步到下一步的fan-out较低时,如最短路径查询中的例子,使用较小的值(如1.0)可能有所帮助。 图分析查询可能会从大于默认值的设置中受益。