WHERE ...
这里唯一的区别是,JOINEXPR 节点被替换为了 FROMEXPR(因此参数名称为 FROM)。
每当生成的扁平化计划树最终包含太多相同级别的节点(表或连接结果)时,规划时间可能会飙升,因为每个节点都需要单独的优化。如果参数 geqo 处于开启状态(默认为开启),则每当同级节点数量达到 geqo_threshold(默认为 12)时,PostgreSQL 将切换到基因搜索。
基因搜索比动态规划方法快得多,但它并不能保证找到最好的计划。该算法有许多可调整的选项,但这应该是另一篇文章的主题。
选择最佳计划
最佳计划的定义因期望的用途而异。当需要完整输出时(例如,生成报表),计划必须优化与查询匹配的所有行的检索。另一方面,如果您只想查看前几行匹配的行(例如,在屏幕上显示),则最佳计划可能完全不同。
PostgreSQL 通过计算两个成本构成来解决这个问题。它们显示在查询计划输出中的 “cost” 一词之后:
Sort (cost=21.03..21.04 rows=1 width=128)
第一个部分,启动成本,是准备执行节点的成本;第二个部分,总成本,表示节点执行的总成本。
选择计划时,规划器首先检查是否正在使用游标(可以使用 DECLARE 命令设置游标,或在 PL/pgSQL 中显式声明)。如果没有,规划器将假定需要全部输出,并选择总成本最低的计划。
否则,如果在使用游标,则规划器将选择一个计划,该计划以最佳方式检索等于匹配行总数的 cursor_tuple_fraction(默认为 0.1)的行数。或者,更具体地说,具有最低值
启动成本 + cursor_tuple_fraction × (总成本 − 启动成本)。
成本计算过程
要估算一个计划的成本,必须单独估算其每个节点。节点成本取决于节点类型(从表中直接读取的成本远低于对表数据进行排序的成本)和处理的数据量(通常,数据越多,成本越高)。虽然节点类型是立即就知道的,但要评估数据量,我们首先需要估计节点的基数(输入行的数量)和选择率(剩余用于输出的行的比例)。为此,我们需要数据的统计信息:表大小、跨列的数据分布。
因此,优化依赖于准确的统计信息,这些统计信息由自动分析进程收集和保持最新状态。
如果准确估计了每个计划节点的基数,则计算的总成本通常与实际成本匹配。常见的规划偏差通常是由基数和选择率估计不正确造成的。这些错误是由不准确、过时或不可用的统计数据引起的,并且在较小程度上,也会由规划器所基于的固有不完善的模型引起。
基数估算是递归执行的。节点基数使用两个值计算:
节点的子节点的基数,或输入行数。
节点的选择率,或输出行与输入行的比例。
基数是这两个值的乘积。
选择率是介于 0 和 1 之间的数字。接近零的选择率值称为高选择率,接近 1 的值称为低选择率。这是因为高选择率消除了较高比例的行,而较低的选择率值会降低阈值,因而丢弃的行更少。
具有数据访问方法的叶节点会首先处理。这就是表大小等统计信息的用武之地。
应用于一个表的条件的选择率取决于条件类型。在最简单的形式中,选择率可以是一个恒定值,但规划器会试图使用所有可用信息来产生最准确的估计。最简单条件的选择率估计会作为基础,使用布尔运算构建的复杂条件,可以使用以下简单公式进行进一步计算:
selx and y = selx sely
selx or y = 1−(1−selx)(1−sely) = selx + sely − selx sely。
在这些公式中,x 和 y 被认为是独立的。如果它们相关,公式仍会被使用,但估计值会不太准确。
对于连接的基数估计,会计算两个值:笛卡尔乘积的基数(两个数据集的基数的乘积)和连接条件的选择率,这反过来又取决于条件类型。
其他节点类型(如排序或聚合节点)的基数计算方式类似。
请注意,较低节点中的基数计算错误会向上传播,导致成本估算不准确,并最终选择出次优的计划。更糟糕的是,规划器只有表上的统计数据,而没有连接结果的统计数据。
成本估算过程也是递归的。子树的成本包括其子节点的成本加上父节点的成本。
节点成本的估算基于其执行的操作的数学模型。已经计算过的基数会用作输入。估算过程会计算启动成本和总成本。
某些操作不需要任何准备,可以立即开始执行。对于这些操作,启动成本将为零。
其他操作可能具有前提条件。例如,排序节点通常需要其子节点中的所有数据才能开始操作。这些节点的启动成本不为零。即使下一个节点(或客户端)只需要一行输出,也必须付出此成本。
成本是规划器的最佳估计。任何规划错误都会影响到成本与实际执行时间的相关性。成本评估的主要目的是,允许规划器在相同条件下比较同一查询的不同执行计划。在任何其他情况下,按成本比较查询(更糟糕的是,对不同的查询)是毫无意义和错误的。比如,考虑下由于统计信息不准确而被低估的成本。更新统计信息 - 成本可能会发生变化,但估算会变得更加准确,并且计划最终也会得到改进。
PostgreSQL 优化