PostgreSQL 原生存储引擎的优势

John Doe 十一月 17, 2025

摘要:在本文中,您将了解 PostgreSQL 原生存储引擎的优势。

目录

an elephant and a dolphin

极致的性能与效率

查询优化器可以基于存储引擎的精确特性(如数据分布、索引类型、页面布局)来制定最优的执行计划。例如,优化器确切地知道某种索引是如何组织和存储的,从而能做出最精准的成本估算。在可插拔架构下,优化器需要做一个“通用”的假设,可能无法发挥某个特定引擎的全部潜力。

查询优化器的成本模型可以与原生存储引擎的特性深度绑定。优化器清楚地知道一次顺序读、一次随机读、一次索引查找的真实代价是多少。PostgreSQL 收集并使用了非常详细的统计信息,包括每列的直方图、最常用值列表、列与列之间的相关性统计。这使得它在判断多条件查询的选择性时远比可插拔存储引擎要准确。

查询执行器的执行计划与原生存储引擎的行为特点紧密耦合,让数据库整体能发挥出极致性能;如:Hash Join、Bitmap Scan 等堆表相关的执行计划。

高度稳定和可靠

统一的 WAL 日志:在原生架构中,只有一个统一的、为整个数据库系统设计的重做日志(Redo Log)和回滚段(Undo Log)。事务管理器和存储引擎共同使用这套日志系统来保证崩溃恢复和事务的原子性、持久性。这避免了在可插拔架构下可能出现的复杂情况(例如,多个存储引擎之间的事务协调问题,即 XA 事务,会带来性能开销和复杂性)。同时,基于 WAL 日志的逻辑复制(发布和订阅)实现也更加高效可靠。

简化的崩溃恢复:由于日志和存储是统一的,崩溃恢复过程是确定且直接的。数据库启动时,按照统一的 WAL 日志重放即可将数据恢复到一致状态。而在可插拔架构中,如果多个引擎都参与了同一个事务,恢复过程会非常复杂。由于 WAL 日志重放是严格顺序执行的,如果有可插拔的存储引擎重放出错,整个数据库系统将会陷入瘫痪。

统一的备份与恢复:备份工具直接与原生存储引擎交互,可以生成物理上或逻辑上完全一致的数据快照。而在可插拔架构中,对不同引擎可能需要不同的备份策略或工具,增加了运维复杂度。

对于原生的存储引擎,由于整个系统是一个完整的、经过充分测试的集成体,其架构一致性更高,出现边缘案例和难以调试的 Bug 的概率相对较低。系统的各个模块经过了多年的协同打磨,稳定性和成熟度通常非常高。

MySQL 可插拔架构的缺陷

查询优化器先天性不足

可插拔架构在优化器和存储引擎之间设立了一个定义良好的 API 接口(例如 MySQL 的handler类)。这面墙虽然带来了灵活性,但也导致了关键信息的丢失和性能开销。

优化器做决策(比如选择哪个索引、使用哪种连接顺序)的核心依据是统计信息。优化器只能通过存储引擎提供的 API 来询问统计信息。为了保持通用性,这个 API 通常是简单和粗粒度的。例如:

  • records_in_range(): 通过向存储引擎询问一个索引范围大概有多少条记录来估算成本。对于像 InnoDB 这样的 B+Tree 引擎,这通常是通过在非叶子节点上进行采样估算的,误差可能很大。
  • info(): 获取表的粗略统计信息,如总行数(这在实际操作中也可能是一个估值)。

结果就是:MySQL 优化器常常在信息不全或信息不准的情况下做决策。对于简单查询(如主键查询、单表简单过滤),这种误差影响不大。但对于涉及多表连接、复杂过滤条件的查询,误差会层层累积,导致优化器选择一个非常糟糕的执行计划。

另外,优化器的成本模型需要将各种操作(磁盘 I/O、CPU 计算)转化为一个可比较的成本。

MySQL 的成本模型是相对通用和硬编码的。它试图为所有存储引擎建立一个统一的成本标准。但不同的引擎(如 InnoDB 和 MyISAM)其性能特征天差地别。这意味着成本模型可能无法准确反映特定引擎(即使是默认的 InnoDB)的真实情况。

结果就是:优化器可能认为“使用索引 A 再进行排序”的成本低于“使用索引 B”,但实际上对于 InnoDB 来说,前者可能慢得多。因为它无法理解 InnoDB 的聚簇索引、Change Buffer 等机制带来的细微性能影响。

需要补充的是:MySQL 团队清楚地认识到了这个问题,并且近年来一直在努力“拆掉这面墙”:

  • InnoDB 成为事实标准:随着 MyISAM 的没落,MySQL 将系统表切换成使用 InnoDB,几乎变成了一个“以 InnoDB 为原生引擎”的数据库。这也让他们可以针对 InnoDB 进行深度优化。
  • 持续优化成本模型:MySQL 8.0 引入了直方图(Histograms),提供了更精细的列数据分布信息。
  • 优化器增强:每个大版本都在增强优化器,比如引入了哈希连接(Hash Join)、反连接(Anti-Join)等新的执行策略,并不断改进成本估算算法。

虽然 MySQL 正在努力弥补,但其架构的历史包袱使得这个过程比从头设计的系统要艰难得多。

逻辑复制延迟的核心症结

逻辑复制(Binlog)是 Server 层的组件,它独立于底层的存储引擎。为了确保所有引擎的数据一致性,Binlog 必须在事务提交后、在存储引擎之上进行记录。这种上层的、与引擎解耦的设计,天然导致了它无法深刻理解存储引擎内部的页面级变更。它只能看到一个全局的、线性的操作序列。

相比之下,物理复制的系统(如 Oracle Data Guard,SQL Server AlwaysOn)或 InnoDB 集群使用的底层日志传输,其复制的是存储引擎物理页面的变化,从库更多是进行数据恢复而非 SQL 重放,因此更容易保持与主库相似的并行度和性能。

MySQL 逻辑复制延迟高的根本原因,深植于其可插拔存储引擎架构。这种架构导致复制机制(Server 层的 Binlog)与存储引擎(InnoDB)解耦,只能采用效率较低的 SQL 重放模式。

最终结果就是,逻辑复制成为了一个在数据库系统外围运行的、相对笨重和低效的数据同步机制,其性能天花板远远低于与存储引擎深度集成的原生复制方案。虽然 MySQL 通过并行复制、WRITESET 等技术在不断修补,但只要其核心架构不变,这个问题就很难被根除。

总结

简单来说,原生存储引擎的优势在于其深度集成所带来的极致性能和简洁性,而可插拔存储引擎的优势在于其灵活性。

原生存储引擎是与数据库管理系统的其余部分(如查询优化器、执行器、事务管理器、恢复模块等)共同设计,构成紧密耦合的存储管理组件。典型的代表是 Oracle、SQL Server、DB2 等商业数据库产品。

可插拔存储引擎的优势在于灵活性和生态,它允许数据库适应不同的工作负载(如 OLTP、OLAP、KV 存储等),并促进了存储技术的创新和竞争。MySQL 的繁荣生态在很大程度上得益于其可插拔的存储引擎架构。