标识查询处理组件
执行查询有四个单独的阶段。 按照执行顺序,这些阶段包括:
- 解析
- 转换(重写器)
- 规划
- 执行
分析器
分析程序负责检查查询字符串是否具有有效的语法。 分析程序有两个主要部分:
- gram.y,由一组语法规则和相应的操作组成。
- scan.1词法器,识别标识符和 SQL 关键字。 每个关键字或标识符都会触发令牌的创建,并将其交给解析器。
分析器生成一个查询树,它将查询分成可识别的部分,以了解涉及哪些表、应用了哪些筛选器等。查询树的各个部分包括:
- 命令类型 - SELECT、INSERT、UPDATE 或 DELETE。
-
Range 表项(RTE) - 关系列表、
ie
表、子查询、联接结果等。在 SELECT 语句中,这些项显示在 FROM 关键字后面。 - 结果关系 - 命令 INSERT、UPDATE 和 DELETE 命令的结果关系是更改生效的表或视图。
- 目标列表 - 查询的结果,在关键字 SELECT 和 FROM 之间标识。 DELETE 命令不会生成结果,因此 Planner 会添加一个特殊条目,以允许执行程序查找要删除的行。 INSERT 命令标识应进入结果关系的新行。 对于 UPDATE 命令,目标列表描述应替换旧行的新行。
- 限定 - 一个布尔值,指明是否应执行最终结果行的操作。 它对应于 SQL 语句的 WHERE 子句。
- 联接树 - 此树可以是 FROM 项的列表。 可以按任意顺序完成联接,也可以按特定顺序(如外部联接)完成联接。
- 其他 - 此阶段不相关的项,例如 ORDER BY 子句。
重写器
解析器的输出将传递给 转换或重写器 进程;如果发现错误,则返回错误信息。
查询重写程序通过向其应用 规则来重写查询文本。 重写程序考虑规则,然后将修改后的查询传递给查询规划器。 行级安全保障在此阶段实现。
例如,SELECT 上的规则始终作为最后一步应用,包括 INSERT、UPDATE 和 DELETE 查询。 规则还意味着 UPDATE 查询不会覆盖现有行,而是插入新行,并且旧行处于隐藏状态。 事务提交后,真空进程可以删除隐藏行。
计划
规划器的工作是获取查询规则并了解可以执行查询的不同方式中的哪一种是最快的。
规划器创建一个计划树结构,其中节点表示数据的物理操作。
PostgreSQL 使用基于成本的查询优化器来查找查询的最佳计划。 规划器评估各种执行计划,并估计所需的资源量,例如 CPU 周期、I/O作等。然后,此估算值转换为单位,称为 计划成本。 选择了成本最低的计划。
但是,随着联接数的增加,可能的计划数量呈指数级增长。 即使对于相对简单的查询,评估每个可能的计划也是不可能的。 启发式和算法用于限制可能的方案数量。 结果是所选计划可能不是最佳计划。 但是,它接近最优,并在合理的时间内被选择。
成本是规划器的最佳估算值。 成本估算的目的是 在 相同 条件中比较 相同 查询的不同执行计划。 规划器使用对表和行收集的统计信息来生成查询的成本估算值。 若要使成本估算准确,统计信息必须最新。
最新统计信息
查询优化器的规划器组件使用有关表和行的统计信息来生成准确的成本估算。
ANALYZE 收集有关数据库表的统计信息,并将结果存储在 pg_statistic 系统目录中。 如果需要,请运行 ANALYZE:
- 您已禁用 自动清理功能(该功能通常自动分析表)
- 您禁用了 autovacuum,但最近尚未运行 ANALYZE
- 前述两者中的任一,并且存在许多 INSERTS、UPDATES 或 DELETE 语句。
成本估算依赖于 up-to日期统计信息,如果统计信息过期,可以选择效率低下的计划。 如果未将参数传递给 ANALYZE,则会检查数据库中的每一个表。
ANALYZE 的语法为:
ANALYZE [ VERBOSE ] [ ***table*** [ ( ***column*** [, ...] ) ] ]
VERBOSE 显示进度消息,以显示正在分析的表以及一些统计信息。
安排在低使用率时段每天运行 VACUUM 和 ANALYZE。 ANALYZE 可以与其他活动并行运行,因为它只需要目标表上的读取锁。
执行者
此阶段采用规划器创建的计划,并递归处理以提取所需的行集。 每次调用计划节点时,执行程序必须输出一行,或报告它已完成。
执行程序计算所有四种 SQL 查询类型:
- 选择
- 插入
- 更新
- 删除
对于 SELECT,执行程序将每一行作为结果集返回给客户端。
对于 INSERT,每个返回的行都插入到指定的表中。 此任务是在名为 ModifyTable 的特殊顶级计划节点中完成的。
对于 UPDATE,每个计算行都包含所有更新的列值,以及目标行的行 ID。 数据将发送到 ModifyTable 节点,该节点创建更新的行并将旧行标记为已删除。
对于 DELETE,计划中唯一返回的列是行 ID。 ModifyTable 节点使用行 ID 将行标记为已删除。