Christophe Pettus 最近发了一篇更正声明:他此前在周三的文章中声称 Snowflake Postgres 是一个带有私有存储层的 fork,这个说法是错的。事实是——Snowflake Postgres 就是社区版 Postgres,没有魔改存储引擎,没有私有 fork。
这个更正看似只是事实层面的修补,但它背后牵出的技术话题值得深挖:Postgres 的 Table Access Methods(表访问方法)到底是什么?为什么有人会误以为 Snowflake 用了私有存储层?理解这一点,对评估任何"托管 Postgres"服务的真实面目至关重要。
误读是怎么产生的
Postgres 12 引入了 Table Access Methods API,允许第三方实现替代默认的 heap 存储引擎。这意味着理论上,一个云厂商可以写一个专有的 access method,把数据存进自研的列存引擎或对象存储,然后宣称"我们跑的是 Postgres"。
Pettus 原文大概顺着这个思路,推测 Snowflake 的 Postgres 产品用了私有 access method 替换了社区版的 heap 存储。但事实并非如此——Snowflake Postgres 用的就是标准的 heap access method,和你在本地 pg_ctl initdb 出来的数据库一模一样。
这个误读提醒我们:Table Access Methods API 的存在,不等于有人真的在用它替换存储层。 目前生产环境中,绝大多数 Postgres 实例仍然只用默认的 heap。
Table Access Methods 到底是什么
Table Access Methods 是 Postgres 定义存储引擎行为的抽象接口。它决定了:
- 数据页怎么组织(page layout)
- 元组怎么插入、更新、删除
- 索引怎么和表数据关联
- Vacuum 怎么回收空间
默认且几乎唯一在用的 access method 是 heap——就是大家熟悉的 MVCC 行存储,8KB 页面,自由空间映射(FSM)和可见性映射(VM)那一套。
你可以在 pg_class 中查看任何表绑定的 access method:
-- 查看当前数据库所有表的 access method
SELECT relname, amname
FROM pg_class c
JOIN pg_am a ON c.relam = a.oid
WHERE c.relkind = 'r'
ORDER BY relname;
在标准社区版 Postgres 上,结果里 amname 列只会出现 heap。
实操:检查你的 Postgres 是不是"原味"的
不管你用的是 AWS RDS、Azure Flexible Server、Snowflake Postgres 还是自建实例,下面这套检查可以帮你确认存储层有没有被替换:
# 1. 连接到你的托管 Postgres
psql -h your-host -U your-user -d your_db
# 2. 列出系统注册的所有 access methods
SELECT amname, amhandler, amtype
FROM pg_am;
# 3. 在社区版 16 上,你应该只看到:
# amname | amhandler | amtype
# --------+----------------------+--------
# heap | heap_tableam_handler | t
# (1 row)
#
# 如果出现其他 amname 且 amtype = 't',
# 说明有人注册了自定义表访问方法。
# 4. 检查是否有表绑定了非 heap 的 access method
SELECT relname, amname
FROM pg_class c
JOIN pg_am a ON c.relam = a.oid
WHERE c.relkind = 'r' AND amname != 'heap';
# 5. 如果上面的查询返回 0 行,你的存储层就是原味社区版。
再补一个更底层的验证——看 pg_settings 中与存储相关的参数是否被魔改:
-- 检查默认 table access method 设置
SELECT name, setting, source
FROM pg_settings
WHERE name = 'default_table_access_method';
-- 社区版默认值是 'heap',source 是 'default'
-- 如果 source 是 'configuration file' 且值不是 'heap',
-- 就要追问厂商改了什么
为什么这个澄清对选型有影响
如果 Snowflake Postgres 真是私有存储层的 fork,那意味着:
- 社区版工具链(pg_dump、pg_upgrade、逻辑复制)可能不兼容
- 行为细节可能偏离文档
- 迁出时数据格式可能无法直接用社区版加载
但既然它就是社区版 Postgres,这些风险就不存在。你可以用标准 pg_dump 导出,用标准 pg_restore 导入到任何其他社区版实例。
不过,"是社区版"不等于"没有差异"。托管服务通常会在 配置、扩展、权限 上做调整:
-- 查看托管服务预装的扩展
SELECT name, default_version, comment
FROM pg_available_extensions
ORDER BY name;
-- 查看哪些扩展被自动 preload
SELECT name, setting
FROM pg_settings
WHERE name = 'shared_preload_libraries';
这些差异是正常的运维层调整,不涉及存储引擎替换,不会影响数据兼容性。
评估托管 Postgres 的清单
下次看到任何"托管 Postgres"产品,用这几步快速判断它的真实面目:
| 检查项 | 怎么查 | 正常结果 |
|---|---|---|
| 表访问方法 | SELECT amname FROM pg_am WHERE amtype='t' |
只有 heap |
| 默认 access method | SHOW default_table_access_method |
heap |
| 版本号 | SELECT version() |
标准社区版版本字符串 |
| 预装扩展 | SELECT name FROM pg_available_extensions |
社区版 contrib + 常见第三方 |
| 超级用户权限 | SELECT current_user, usesuper FROM pg_user WHERE usename = current_user |
托管服务通常不给 true superuser |
核心原则:只要 pg_am 里没有自定义表访问方法,default_table_access_method 是 heap,你的数据就存在标准存储格式里,随时可以迁移。
Pettus 的更正本身是个小事件,但它暴露了一个普遍问题——云厂商的营销话术容易让人把"托管"和"魔改"混为一谈。Table Access Methods API 给了厂商魔改的可能性,但截至目前,主流托管服务都没有走这条路。遇到声称"基于 Postgres"的产品,用上面的 SQL 验一遍,比读宣传页靠谱得多。