2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: 开发版
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1

19.7. 查询规划 #

19.7.1. 规划器方法配置 #

这些配置参数提供了一种粗略的方法来影响查询优化器选择的查询计划。如果优化器为特定查询选择的默认计划不是最优的,那么使用这些配置参数之一强制优化器选择不同计划是一种临时解决方案。改进优化器选择计划质量的更好方法包括调整规划器成本常量(参见 Section 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 键以匹配输入路径的路径键的能力。默认值为 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) #

启用或禁用查询规划器使用仅索引扫描计划类型(参见 Section 11.9)。默认值为 on。要让查询规划器考虑仅索引扫描,必须同时启用 enable_indexscan 设置。

enable_material (boolean) #

启用或禁用查询规划器使用物化。完全禁止物化是不可能的,但关闭此变量会阻止规划器插入物化节点,除非是为了正确性所必需的情况。默认值为 on

enable_memoize (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.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 成本的重要性,CPU 成本由以下参数描述。

机械磁盘存储的随机访问通常比顺序访问的四倍还要昂贵。但是,使用了较低的默认值(4.0),因为假设大多数对磁盘的随机访问(例如索引读取)都在缓存中。默认值可以看作是将随机访问建模为比顺序访问慢 40 倍,同时期望 90% 的随机读取被缓存。

如果您认为 90% 的缓存率不适合您的工作负载,您可以增加 random_page_cost 以更好地反映随机存储读取的实际成本。相应地,如果您的数据很可能完全在缓存中(例如,当数据库小于服务器总内存时),则可以减小 random_page_cost。随机读取成本相对于顺序读取成本较低的存储(例如,固态硬盘)也可以通过较低的 random_page_cost 值(例如 1.1)进行更好的建模。

提示

尽管系统允许您将 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。默认值为 8MB (8MB)。

min_parallel_index_scan_size (integer) #

设置必须扫描的索引数据的最小量,以便考虑并行扫描。请注意,并行索引扫描通常不会触及整个索引;重要的是规划器认为实际将被扫描的页面数量。此参数还用于决定特定索引是否可以参与并行 VACUUM。请参阅 VACUUM。如果此值没有单位,则假定为块,即 BLCKSZ 字节,通常为 8kB。默认值为 512kB (512kB)。

effective_cache_size (integer) #

设置规划器对单个查询可用磁盘缓存的有效大小的假设。这被纳入使用索引的成本估计中;较高的值会使索引扫描更可能被使用,较低的值会使顺序扫描更可能被使用。设置此参数时,您应同时考虑 PostgreSQL 的共享缓冲区和将用于 PostgreSQL 数据文件的内核磁盘缓存部分,尽管某些数据可能同时存在于两者中。此外,还应考虑不同表上并发查询的预期数量,因为它们必须共享可用空间。此参数不会影响 PostgreSQL 分配的共享内存大小,也不会保留内核磁盘缓存;它仅用于估计目的。系统也不会假设数据在查询之间保留在磁盘缓存中。如果此值没有单位,则假定为块,即 BLCKSZ 字节,通常为 8kB。默认值为 4GB (4GB)。(如果 BLCKSZ 不是 8kB,则默认值与其成比例缩放。)

jit_above_cost (floating point) #

设置 JIT 编译激活的查询成本(如果已启用,请参阅 Chapter 30)。执行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 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 使用的池大小,即遗传种群中的个体数量。它至少必须为两个,并且有用的值通常在 100 到 1000 之间。如果将其设置为零(默认设置),则会根据 geqo_effort 和查询中的表数量选择一个合适的值。

geqo_generations (integer) #

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

geqo_selection_bias (floating point) #

控制 GEQO 使用的选择偏差。选择偏差是种群内的选择压力。值可以从 1.50 到 2.00;后者是默认值。

geqo_seed (floating point) #

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

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.12.5

cursor_tuple_fraction (floating point) #

设置规划器对游标检索的行数的估计比例。默认值为 0.1。此设置值越小,规划器越倾向于为游标使用快速启动计划,该计划将快速检索前几行,但可能需要很长时间才能检索完所有行。值越大,对总估计时间的重视程度越高。在最大设置 1.0 下,游标的规划方式与常规查询完全相同,仅考虑总估计时间,而不考虑何时可以返回第一行。

from_collapse_limit (integer) #

如果生成的 FROM 列表项不超过此数量,规划器会将子查询合并到上层查询中。较小的值会减少规划时间,但可能会产生次优的查询计划。默认值为 8。有关更多信息,请参阅 Section 14.3

将此值设置为 geqo_threshold 或更高可能会触发 GEQO 规划器的使用,从而导致非最优计划。请参阅 Section 19.7.3

jit (boolean) #

决定是否JIT编译可以使用 PostgreSQL(如果可用,请参阅 Chapter 30)。默认值为 on

join_collapse_limit (integer) #

当结果项列表不超过此数量时,规划器会将显式 JOIN 构造(除了 FULL JOIN)重写为 FROM 项列表。较小的值会减少规划时间,但可能会产生次优的查询计划。

默认情况下,此变量设置为与 from_collapse_limit 相同,这对于大多数用途都是合适的。将其设置为 1 会阻止对显式 JOIN 进行任何重新排序。因此,查询中指定的显式连接顺序将是关系连接的实际顺序。由于查询规划器并不总是选择最优的连接顺序,因此高级用户可以选择暂时将此变量设置为 1,然后显式指定所需的连接顺序。有关更多信息,请参阅 Section 14.3

将此值设置为 geqo_threshold 或更高可能会触发 GEQO 规划器的使用,从而导致非最优计划。请参阅 Section 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。较小的值(如 1.0)在递归具有较低的扇出(从一步到下一步)时可能很有帮助,例如在最短路径查询中。图分析查询可能受益于大于默认值的值。

提交更正

如果您在文档中看到任何不正确、与您对特定功能的使用经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。