梧桐数据库(WuTongDB):PostgreSQL 优化器简介

server/2024/9/23 5:12:58/

PostgreSQL 的查询优化器是一个高度复杂且功能强大的组件,负责将 SQL 查询转换为高效的执行计划。它采用了基于代价(Cost-based)的方法来评估查询计划的执行成本,并选择代价最小的执行方案。下面详细讲解 PostgreSQL 优化器的关键技术:

1. 查询规划过程

PostgreSQL 查询优化器的工作过程主要分为以下几个步骤:

1.1 解析(Parsing)

首先,PostgreSQL 将 SQL 查询字符串转换为解析树(Parse Tree)。这一步主要是语法分析,确保 SQL 语法正确。

1.2 语义分析(Semantic Analysis)

解析树会经过语义分析,进行合法性检查,例如检查表、列是否存在,数据类型是否匹配等。这个阶段的输出是一个增强的查询树,称为查询树(Query Tree),它是逻辑查询的初步表示。

1.3 重写规则(Rewrite Rules)

在这个阶段,PostgreSQL 会根据规则系统(Rule System)来重写查询。比如视图(Views)的实现就是通过查询重写来替代查询中的视图部分。此时生成的仍然是逻辑查询表示。

1.4 规划和优化(Planning and Optimization)

在规划和优化阶段,PostgreSQL 的优化器会生成多个可能的查询执行计划,并根据代价模型来评估每个计划的执行成本。优化器的目标是选择代价最低的计划。这一过程可以细分为以下两个部分:

  • 逻辑计划生成(Logical Plan Generation): PostgreSQL 会根据 SQL 查询生成一个逻辑计划,描述查询的操作和操作顺序。
  • 物理计划生成(Physical Plan Generation): 逻辑计划会转换为物理计划,指定具体的操作如何在物理层面实现,如如何访问表数据(顺序扫描、索引扫描等),如何执行连接(嵌套循环连接、哈希连接等)。

2. 基于代价的优化器(Cost-based Optimizer)

PostgreSQL 优化器使用基于代价的优化方法(CBO, Cost-Based Optimizer)。其核心思想是为每个候选执行计划估算执行代价,代价越低的计划越可能被选择为最终的执行计划。

2.1 代价模型

代价模型是 PostgreSQL 优化器的核心。每个操作(如扫描表、执行连接、排序等)都有一个相应的代价函数,用于计算其执行代价。代价通常基于以下几个因素:

  • I/O 成本: 读取数据页的次数和方式(顺序读取 vs. 随机读取)。
  • CPU 成本: 处理每行数据所需的 CPU 资源,包括计算表达式、执行条件过滤等。
  • 内存成本: 查询执行过程中所需的内存消耗,特别是涉及排序或哈希操作时。
  • 网络成本: 在分布式查询的场景中,传输数据的网络延迟也是代价的一部分。
2.2 扫描策略

PostgreSQL 提供了多种扫描表的方式,优化器会根据代价模型选择最合适的扫描策略:

  • 顺序扫描(Sequential Scan): 逐行扫描整个表,适用于表较小或需要扫描大部分数据的情况。
  • 索引扫描(Index Scan): 通过索引访问表中的特定行,适用于表较大、但只需要读取少量数据的情况。
  • 索引仅扫描(Index-Only Scan): 如果查询只需要索引中已有的数据列,可以避免访问表本身,只扫描索引。
  • 位图扫描(Bitmap Scan): 结合位图索引批量访问数据页,适用于需要读取多行数据但分布较散的情况。
2.3 连接策略

PostgreSQL 支持多种连接算法,优化器根据代价选择最优的连接方式:

  • 嵌套循环连接(Nested Loop Join): 遍历一个表,并为每行在另一个表中查找匹配行,适用于小型表的连接或存在有效索引的情况。
  • 哈希连接(Hash Join): 为一个表构建哈希表,然后在另一个表中查找匹配项,适用于较大表且没有合适索引的情况。
  • 合并连接(Merge Join): 首先对两个表进行排序,然后逐步合并匹配行,适用于已经按连接条件排序的数据。
2.4 子查询优化

PostgreSQL 优化器还支持将子查询进行优化,包括将子查询转换为连接(Join),或者使用半连接(Semi Join)等技术。此外,它还可以根据上下文将子查询内联,提高执行效率。

3. 查询优化技术

PostgreSQL 采用了多种优化技术来提升查询性能,包括但不限于以下几种:

3.1 常量折叠与简化(Constant Folding)

在查询执行前,PostgreSQL 会对查询中的常量表达式进行计算并替换,以减少不必要的计算。例如,SELECT * FROM table WHERE 1 + 2 = 3; 会在查询优化阶段被简化为 SELECT * FROM table WHERE TRUE;

3.2 投影推送(Projection Pushdown)

PostgreSQL 优化器会尽可能地将投影操作(即选择需要的列)推送到更靠近数据源的地方,减少传递无用数据的开销。

3.3 谓词推送(Predicate Pushdown)

谓词推送是一种将过滤条件尽可能推到更早的执行步骤中的技术。例如,将 WHERE 条件尽可能地应用于扫描表的阶段,以减少处理的数据量。

3.4 连接重排序(Join Reordering)

在多表连接的查询中,PostgreSQL 优化器会尝试不同的连接顺序,并选择代价最低的连接顺序。

3.5 通用子表达式消除(Common Subexpression Elimination, CSE)

PostgreSQL 能够识别查询中重复计算的部分,并将其提取为一个子查询,以避免重复执行相同的计算。

4. 统计信息

PostgreSQL 优化器依赖表的统计信息来估算每个查询操作的代价。统计信息主要包括表中数据的分布情况,如表的大小、每列的值分布情况、数据的唯一性等。这些统计信息可以通过 ANALYZE 命令进行收集和更新。

  • 元组数量(Number of Rows): 表中元组的数量是决定查询代价的关键因素之一。
  • 数据分布(Data Distribution): 通过分析每列中的数据分布,优化器能够更好地估计条件选择的有效性。例如,在查询条件 WHERE age > 30 中,优化器会根据 age 列的分布来估算需要扫描的行数。
  • 数据倾斜(Data Skew): 如果某些值在列中的出现频率远高于其他值,优化器会基于这些倾斜信息来调整代价估算。

5. 并行查询(Parallel Query)

PostgreSQL 支持并行查询优化,特别是对于大数据集的处理。优化器会评估是否有必要将查询任务分解为多个并行执行的子任务,并生成相应的并行执行计划。并行化技术适用于顺序扫描、哈希连接和聚合等操作。

6. 外部表与分布式查询

对于外部表(例如通过 FDW 访问的远程数据源),PostgreSQL 优化器也能够评估远程数据访问的代价,并尝试将部分查询下推到远程系统执行,以减少网络开销。

7. 增量查询优化(Incremental Query Optimization)

PostgreSQL 还支持增量优化,即在优化阶段不必一次性生成完整的执行计划,而是可以在查询执行时根据当前的数据和统计信息动态调整执行策略。


产品简介

  • 梧桐数据库(WuTongDB)是基于 Apache HAWQ 打造的一款分布式 OLAP 数据库。产品通过存算分离架构提供高可用、高可靠、高扩展能力,实现了向量化计算引擎提供极速数据分析能力,通过多异构存储关联查询实现湖仓融合能力,可以帮助企业用户轻松构建核心数仓和湖仓一体数据平台。
  • 2023年6月,梧桐数据库(WuTongDB)产品通过信通院可信数据库分布式分析型数据库基础能力测评,在基础能力、运维能力、兼容性、安全性、高可用、高扩展方面获得认可。

点击访问:
梧桐数据库(WuTongDB)相关文章
梧桐数据库(WuTongDB)产品宣传材料
梧桐数据库(WuTongDB)百科


http://www.ppmy.cn/server/120642.html

相关文章

【有啥问啥】深度剖析:大模型AI时代下的推理路径创新应用方法论

深度剖析:大模型AI时代下的推理路径创新应用方法论 随着大规模预训练模型(Large Pretrained Models, LPMs)和生成式人工智能的迅速发展,AI 在多领域的推理能力大幅提升,尤其是在自然语言处理、计算机视觉和自动决策领…

Linux驱动开发 ——架构体系

只读存储器(ROM) 1.作用 这是一种非易失性存储器,用于永久存储数据和程序。与随机存取存储器(RAM)不同,ROM中的数据在断电后不会丢失,通常用于存储固件和系统启动程序。它的内容在制造时或通过…

【YMatrix、PostgreSQL】常用SQL集-持续更新ing

查看库中所有表信息-去除多余的分区表 SELECT t.table_name FROM information_schema.tables t LEFT JOIN pg_inherits i ON t.table_name i.inhrelid::regclass::text WHERE t.table_schema public AND i.inhrelid IS NULL;使用insert插入时,忽略库中重复数据&am…

植物大战僵尸【源代码分享+核心思路讲解】

植物大战僵尸已经正式完结,今天和大家分享一下,话不多说,直接上链接!!!(如果大家在运行这个游戏遇到了问题或者bug,那么请私我谢谢) 大家写的时候可以参考一下我的代码思…

【力扣 | SQL题 | 每日三题】力扣182

1. 力扣182:查找重复的电子邮箱 1.1 题目: 表: Person ---------------------- | Column Name | Type | ---------------------- | id | int | | email | varchar | ---------------------- id 是该表的主键(具有唯…

【软件工程】系统流程图

一、定义 二、常用符号 例题 选择题

【Linux】简易日志系统

目录 一、概念 二、可变参数 三、日志系统 一、概念 一个正在运行的程序或系统就像一个哑巴,一旦开始运行我们很难知晓其内部的运行状态。 但有时在程序运行过程中,我们想知道其内部不同时刻的运行结果如何,这时一个日志系统可以有效的帮…

Qt:NULL与nullptr的区别(手写nullptr)

前言 发现还是有人不知道NULL 与nullptr的区别,故写此文章。 正文 对于NULL 先看NULL的源码 我们可以看出这段代码是一个典型的预处理器宏定义块,用于处理 NULL 宏的定义。 先看开头 #if defined (_STDDEF_H) || defined (__need_NULL)这行代码检…