由 John Doe 八月 8, 2025
摘要:在本文中,您将了解什么是 PostgreSQL 中的可插拔存储引擎。
目录
什么是表访问方法?
该特性允许对表数据的存储方式进行替代实现。在 PostgreSQL 11 之前,已经为索引数据提供了访问方法,以选择不同的存储方式,例如 B 树或哈希,但没有类似的机制可用于表。
PostgreSQL 12 引入了此特性,因此现在可以为表和索引实现访问方法,从而允许选择不同的表存储机制。
表访问方法公开了 API,允许 PostgreSQL 开发者创建自己的方法。在 PostgreSQL 12 中,传统的堆格式也被改造成了一种表访问方法,并作为默认的表访问方法提供。
PostgreSQL 11 及更早版本的访问机制
表只能通过堆来访问
PostgreSQL 12 及之后版本的访问机制
用户可以指定表访问方法
如何使用表访问方法的接口?
要定义一个表访问方法,请使用CREATE ACCESS METHOD
带上TYPE TABLE
。然后,要让表使用新的访问方法,请在 CREATE TABLE
、CREATE TABLE AS SELECT
或CREATE MATERIALIZED VIEW
的USING
子句中指定它。或者,您可以在 postgresql.conf 文件的参数default_table_access_method
中指定默认表访问方法。
CREATE ACCESS METHOD heap1 TYPE TABLE HANDLER heap_tableam_handler;
CREATE TABLE tbl1(id int, name text) USING heap1 ...;
优势和如何使用
此功能的吸引力包括以下几方面:
- 简洁、可插拔的架构,易于使用且对 PostgreSQL 开发者友好
- 用户可以为每个表指定访问方法
- 为开源和商业数据库的可能性开路
- 在同一数据库中可以使用不同的表访问方法
PostgreSQL 12 仅支持将堆作为表访问方法,但 PostgreSQL 的后续版本预计将提供新的表访问方法,例如列式和内存中的访问方法。
将来,用户将能够为其业务选择合适的表访问方法,例如用于 OLTP 操作的堆表、用于 OLAP 操作的列式表,以及用于超快速搜索处理的内存表。通过为用户提供一个允许他们使用特定表访问方法的接口,数据库系统将能够满足各种业务处理的需求。
与外部数据包装器有什么区别?
外部数据包装器用于访问外部数据,而表访问方法用于访问本地数据。
例如,假设您需要在应用程序中使用列式数据。使用外部数据包装器,您需要使用它来访问包含列式数据的远程服务器(在本例中使用 cstore_fdw),这会降低处理性能。
但是使用表访问方法,可以在本地存储列式表,从而加快处理速度。但请注意,PostgreSQL 17 还不支持列式表的表访问方法。
简而言之,外部数据包装器和表访问方法针对不同的需求。前者允许用户访问远程服务器中从未打算存储在本地的数据,而后者允许用户使用支持的各种方法在本地存储数据。
通过 cstore_fdw 访问外部数据源中的列式数据
通过访问方法接口访问 PostgreSQL 中的列式数据
架构
经过大量代码重构后,PostgreSQL 12 支持了表访问方法的基础架构,允许自定义表数据的存储和访问方式。默认情况下,PostgreSQL 中的所有表都使用传统的堆表(heap),它基于默认 8kB 大小的页面进行存储,这些页面位于默认 1GB 大小的段文件中,并且存储完整的元组版本。简单来说,这意味着即使只更新元组的一个属性,也需要存储一个全新的版本。这也使得清理(vacuum)和自动清理(autovacuum)的工作成本更高。
表访问方法非常实用,因为它基本上允许直接在 PostgreSQL 中插入一种类似于 MySQL 存储引擎的功能,从而能够实现诸如列存储之类的功能,而这正是堆表的弱项。大致可以将其能实现的功能分为两类:
- 经过 PostgreSQL 存储管理器的访问方法,利用现有的共享缓冲区和现有的分页格式。这样做有两个优点:备份和数据校验能自动得到支持。
- 不经过 PostgreSQL 的访问方法,其优点是不依赖 PostgreSQL 的共享缓冲区(分页格式可能会存在问题),因此可以完全依赖操作系统缓存。需要注意的是,此时需要自行添加数据校验、备份等功能的支持。
带有多个可插拔存储引擎的 PostgreSQL 架构,如下所示:
flowchart TD subgraph "SQL 引擎" %% Nodes A("解析器") B("规划器") C("执行器") D("DDL") E(("系统表")) F("表访问方法管理器") %% Edge connections between nodes A --> B --> C A --> D --> E B & C --> E C & E --> F end subgraph "存储引擎" %% Nodes G("HeapAM") H("Zedstore") I("WhatAM") J("缓冲区管理器") K(("缓冲页")) L("存储管理器 (IO)") M("页面缓存 (Page Cache)") N[("磁盘")] %% Edge connections between nodes G & H & I --> J J --> L --> M --> N J --> K end %% Edge connections between nodes F --> G & H & I
无法使用可插拔的 WAL 记录会是一个限制,虽然可以使用通用 WAL,但功能有限且性能不佳。这个问题很难解决,因为与表访问方法不同,WAL 需要在系统表之外注册回调,并且资源管理器 ID(即 WAL 记录的类别)需要有固定值。需要注意的是,不同的访问方法,TID(元组位置)也可能会成为问题。
总结
PostgreSQL 12 引入了表访问方法的接口,它允许 PostgreSQL 用户使用根据其要求定制的方法访问表数据。希望将来看到越来越多的 PostgreSQL 应用程序,能够选择多种与业务特征相匹配的表访问方法。