PostgreSQL 19 Beta 1 深度解析:SQL/PGQ 图查询 + 并行自动清理 + pg_plan_advice——60 项新特性如何让「全球最先进的开源数据库」再次拉开代差
背景:三十而立的 PostgreSQL,为什么 PG19 是最值得期待的一个版本?
2026 年 6 月 4 日,PostgreSQL 全球开发组正式发布了 PostgreSQL 19 Beta 1。这一年恰好是 PostgreSQL 诞生 30 周年——从 1996 年 Michael Stonebraker 在 UC Berkeley 的 POSTGRES 项目起步,到如今稳坐全球最受欢迎开源关系型数据库的宝座,三十年间 PostgreSQL 击败了一个又一个挑战者:MySQL 被 Oracle 收购后社区分裂,MariaDB 始终在功能完整性上慢半拍,而各种 NewSQL 和 NoSQL 数据库虽然在特定场景下表现优异,但在通用性和稳定性上依然无法撼动 PG 的地位。
PG19 为什么特别? 因为它一次性解决了三个困扰社区多年的核心痛点:
- 图查询能力缺失:此前要跑图查询必须引入 Neo4j 或 Apache AGE 扩展,PG19 原生支持 SQL/PGQ 标准,直接在关系型数据上执行属性图查询
- Vacuum 性能瓶颈:大表的 VACUUM 一直是 PG 的老大难问题,PG19 引入并行自动清理 + 智能评分系统 + 边查询边标记可见页的「懒清理」策略
- 查询计划不可控:生产环境最怕执行计划突然跑偏,PG19 的 pg_plan_advice 让你可以「钉死」关键查询的执行计划
加上 INSERT 性能翻倍、REPACK CONCURRENTLY 在线表重建、WAIT FOR LSN 读写一致性保证、SNI 多证书支持等 60+ 项改进,PG19 堪称近年来最「炸裂」的一次大版本更新。
本文将从架构原理到生产级实战,逐项拆解 PG19 的核心新特性。
一、SQL/PGQ:PostgreSQL 正式成为「图数据库杀手」
1.1 什么是 SQL/PGQ?
SQL/PGQ(SQL Property Graph Queries)是 SQL:2023 标准中定义的图查询子标准。它允许你在标准 SQL 语法中定义「属性图」(Property Graph),然后使用 GRAPH_TABLE、MATCH 等语法直接在关系型表上执行图遍历查询。
核心概念:
- 属性图(Property Graph):基于已有的关系表定义顶点(Vertex)和边(Edge),不需要数据迁移
- GRAPH_TABLE:图查询的入口,类似
FROM子句,但内部使用MATCH模式匹配 - MATCH 模式:用
()-[]->()语法描述图模式,类似 Cypher 但嵌入在 SQL 中
1.2 实战:用 SQL/PGQ 构建社交网络分析
假设我们有一个社交网络系统,已有以下关系表:
-- 用户表
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 好友关系表
CREATE TABLE friendships (
user_id BIGINT REFERENCES users(id),
friend_id BIGINT REFERENCES users(id),
since DATE,
PRIMARY KEY (user_id, friend_id)
);
-- 帖子表
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
author_id BIGINT REFERENCES users(id),
content TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
第一步:定义属性图
CREATE PROPERTY GRAPH social_network
VERTEX TABLES (
users
PROPERTIES (id, name, email)
)
EDGE TABLES (
friendships
SOURCE KEY (user_id) REFERENCES users (id)
DESTINATION KEY (friend_id) REFERENCES users (id)
PROPERTIES (since),
posts
SOURCE KEY (author_id) REFERENCES users (id)
PROPERTIES (content, created_at)
);
注意:属性图是元数据定义,不需要复制数据。它只是告诉 PostgreSQL 如何将现有的关系表解释为图结构。
第二步:执行图查询
-- 查找某用户的朋友的朋友(二度人脉)
SELECT friend_of_friend.name
FROM GRAPH_TABLE(social_network
MATCH (u:users) -[f:friendships]-> (fof:users) -[f2:friendships]-> (friend_of_friend:users)
WHERE u.name = '张三'
AND friend_of_friend.name <> '张三'
COLUMNS (friend_of_friend.name)
);
-- 查找互相关注但从未互动的「僵尸好友」
SELECT u1.name, u2.name
FROM GRAPH_TABLE(social_network
MATCH (u1:users) -[f1:friendships]-> (u2:users) -[f2:friendships]-> (u1:users)
WHERE NOT EXISTS (
SELECT 1 FROM posts p
WHERE p.author_id = u1.id
AND p.content LIKE '%' || u2.name || '%'
)
COLUMNS (u1.name, u2.name)
);
1.3 SQL/PGQ vs Neo4j vs Apache AGE:深度对比
| 维度 | SQL/PGQ (PG19) | Neo4j | Apache AGE |
|---|---|---|---|
| 数据迁移 | 无需迁移,基于现有表 | 需要 ETL | 无需迁移,但需导入图格式 |
| 查询语言 | 标准 SQL + MATCH | Cypher(私有) | Cypher(兼容) |
| ACID 事务 | 完整支持 | 支持 | 支持 |
| 混合查询 | 图+关系+全文一体 | 仅图查询 | 图+关系,但语法割裂 |
| 运维成本 | 零额外组件 | 独立集群 | 需安装扩展 |
| 性能(大规模) | 依赖索引优化 | 原生图存储 | 依赖 PG 优化器 |
| 生态成熟度 | 刚发布,待验证 | 10 年积累 | 社区驱动 |
关键结论:SQL/PGQ 的最大价值不是替代 Neo4j,而是让 90% 的简单图查询场景不再需要引入额外的图数据库。对于社交关系分析、知识图谱查询、依赖关系遍历等典型场景,PG19 原生支持已经足够。
二、并行自动清理:终结大表 VACUUM 噩梦
2.1 为什么 VACUUM 是 PG 的阿喀琉斯之踵?
PostgreSQL 使用 MVCC(多版本并发控制)实现事务隔离。每次 UPDATE 或 DELETE 不会立即删除旧数据,而是标记为「死元组」(dead tuple)。VACUUM 的任务就是回收这些死元组占用的空间。
问题在于:对于 TB 级大表,单线程 VACUUM 可能需要数小时,期间:
- 表膨胀导致查询变慢
- 事务 ID 回卷(wraparound)风险
- 长时间锁竞争
2.2 PG19 的三重优化
优化一:并行 VACUUM Worker
-- 集群级配置:最多 4 个并行 VACUUM worker
ALTER SYSTEM SET autovacuum_max_parallel_workers = 4;
-- 表级配置:大表使用 3 个并行 worker
ALTER TABLE big_events SET (autovacuum_parallel_workers = 3);
-- 查看并行 VACUUM 进度
SELECT pid, relname, phase,
heap_blks_total, heap_blks_scanned,
num_dead_tuples
FROM pg_stat_progress_vacuum v
JOIN pg_class c ON v.relid = c.oid;
并行 worker 来自现有的 max_parallel_workers 资源池,不会额外消耗资源。默认关闭,需要显式启用。
优化二:智能评分系统
PG19 引入了全新的 autovacuum 评分算法,不再是简单的「死元组超过阈值就清理」,而是综合考虑:
- 死元组占比
- 距上次 VACUUM 的时间
- 表的写入频率
- 系统负载
这让有限的 VACUUM 资源优先投入到最需要的表上。
优化三:查询时标记可见页(Lazy Visibility)
这是 PG19 最巧妙的优化之一:当查询扫描到某个页面时,如果该页面的所有元组都对当前事务可见,系统会顺手将整个页面标记为 all-visible,从而减少未来 VACUUM 的工作量。
-- 查看页面可见性状态
SELECT relname,
n_live_tup, n_dead_tup,
round(n_dead_tup::numeric / GREATEST(n_live_tup, 1) * 100, 2) AS dead_pct
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;
2.3 REPACK CONCURRENTLY:在线表重建,零停机
PG19 新增的 REPACK 命令是 pg_repack 扩展的官方内置版本:
-- 在线重建表,消除碎片,不阻塞读写
REPACK TABLE CONCURRENTLY big_events;
-- 重建索引
REPACK INDEX CONCURRENTLY idx_events_created;
与传统 VACUUM FULL 相比,REPACK CONCURRENTLY:
- 不需要 ACCESS EXCLUSIVE 锁
- 使用额外的临时空间完成重建
- 重建完成后原子切换
三、pg_plan_advice:给执行计划装上「方向盘」
3.1 执行计划跑偏:DBA 的深夜噩梦
在生产环境中,最恐怖的事情莫过于一条跑了三年的好好的 SQL,突然因为统计信息变化、数据分布偏移或者 PG 小版本升级,执行计划从 Index Scan 变成了 Seq Scan,查询时间从 10ms 飙到 10s。
PG19 引入的 pg_plan_advice 扩展让你可以为关键查询「锁定」执行计划。
3.2 实战:锁定关键查询的执行计划
-- 启用 pg_plan_advice 扩展
CREATE EXTENSION pg_plan_advice;
-- 为特定查询绑定执行计划
SELECT pg_plan_advice_add(
query_id := 'abc123def456', -- 查询的唯一标识
plan := $$Seq Scan on users -- 指定的执行计划
Filter: (id = 42)
Rows: 1$$
);
-- 使用 pg_stash_advice 基于查询标识自动应用建议
CREATE EXTENSION pg_stash_advice;
-- 查看已有的 plan advice
SELECT * FROM pg_plan_advice_list();
3.3 pg_plan_advice vs pg_hint_plan
| 维度 | pg_plan_advice (PG19 内置) | pg_hint_plan (第三方) |
|---|---|---|
| 安装 | 内置扩展 | 需单独编译安装 |
| 粒度 | 基于 query_id 绑定 | 基于 SQL 文本 hint |
| 持久化 | 自动持久化到系统目录 | 依赖 SQL 注释 |
| 维护成本 | 低,与 PG 版本同步 | 需跟踪兼容性 |
| 灵活性 | 完整计划绑定 | 提示优化器选择 |
四、INSERT 性能翻倍:外键检查不再拖后腿
4.1 外键检查的性能陷阱
在有外键约束的表上执行批量 INSERT 时,每一行插入都需要检查外键引用的父表是否存在对应记录。当父表数据量很大时,这些检查会成为严重的性能瓶颈。
PG19 通过以下优化实现了外键场景下 INSERT 性能的 2 倍提升:
- 批量外键检查缓存:将同一批次 INSERT 中的外键检查合并,减少对父表的重复扫描
- 优化的锁获取策略:减少外键检查期间的锁竞争
- 智能统计信息利用:利用已有的统计信息快速判断外键是否存在
4.2 性能对比测试
-- 创建测试表
CREATE TABLE parent (id BIGSERIAL PRIMARY KEY, data TEXT);
CREATE TABLE child (
id BIGSERIAL PRIMARY KEY,
parent_id BIGINT REFERENCES parent(id),
value TEXT
);
-- 填充父表
INSERT INTO parent (data)
SELECT 'data_' || i FROM generate_series(1, 1000000) i;
-- PG18 vs PG19 批量插入对比
-- PG18: ~15,000 rows/sec
-- PG19: ~32,000 rows/sec (2.1x)
INSERT INTO child (parent_id, value)
SELECT (random() * 999999 + 1)::BIGINT, 'value_' || i
FROM generate_series(1, 100000) i;
五、更多重磅特性速览
5.1 WAIT FOR LSN:读写一致性的终极方案
在读写分离架构中,最大的挑战是「读副本可能还没同步到最新写入」。PG19 的 WAIT FOR LSN 命令彻底解决了这个问题:
-- 写入后获取当前 LSN
INSERT INTO orders (product, amount) VALUES ('iPhone', 999);
SELECT pg_current_wal_lsn();
-- 在读副本上等待该 LN 同步完成
WAIT FOR LSN '0/12345678';
-- 现在可以安全地读取最新数据
SELECT * FROM orders WHERE product = 'iPhone';
相比之前的 synchronous_commit = remote_apply,WAIT FOR LSN 的优势:
- 粒度更细:可以只等待特定 LSN,而非所有写入
- 不影响写入性能:写入时不需要等待副本确认
- 应用层可控:可以根据业务场景灵活决定何时等待
5.2 GROUP BY ALL:告别繁琐的聚合查询
-- 旧写法:手动列出所有非聚合列
SELECT department, team, role, COUNT(*), AVG(salary)
FROM employees
GROUP BY department, team, role;
-- PG19 新写法
SELECT department, team, role, COUNT(*), AVG(salary)
FROM employees
GROUP BY ALL;
5.3 INSERT ... ON CONFLICT DO SELECT ... RETURNING
-- 插入或获取已存在的记录(upsert + 返回冲突行)
INSERT INTO users (email, name)
VALUES ('test@example.com', 'Test User')
ON CONFLICT (email)
DO SELECT id, email, name, 'existing' AS status
RETURNING *;
5.4 SNI 多证书支持
-- pg_hosts.conf 配置
-- hostname1 /path/to/cert1.crt /path/to/key1.key
-- hostname2 /path/to/cert2.crt /path/to/key2.key
-- 一个 PG 实例可以为不同域名提供不同的 TLS 证书
-- 非常适合多租户场景
5.5 数据校验和在线开关
-- 不需要停机即可启用数据校验和
ALTER SYSTEM SET data_checksums = on;
-- 或禁用
ALTER SYSTEM SET data_checksums = off;
5.6 JIT 默认关闭
PG19 将 JIT 编译默认关闭了。这是一个务实的决定——JIT 在复杂查询上确实有性能提升,但对于 OLTP 场景,JIT 的编译开销反而会拖慢简单查询。
5.7 lz4 默认压缩
-- PG19 默认使用 lz4 压缩 TOAST 数据
-- 相比 pglz,lz4 压缩速度快 3-5 倍,解压速度更快
ALTER SYSTEM SET default_toast_compression = 'lz4';
5.8 FOR PORTION OF 时态查询增强
PG18 引入了时态表(temporal tables)支持,PG19 扩展了 FOR PORTION OF 语法:
-- 更新某段时间内的数据
UPDATE employee_history
SET salary = 75000
FOR PORTION OF valid_between
FROM '2026-01-01' TO '2026-06-30'
WHERE employee_id = 42;
-- 删除某段时间内的记录
DELETE FROM audit_log
FOR PORTION OF event_period
FROM '2025-01-01' TO '2025-06-30';
六、逻辑复制与查询联邦增强
6.1 序列值自动复制
-- PG19 逻辑复制现在自动包含序列值
-- 不再需要手动同步序列
CREATE PUBLICATION my_pub FOR ALL TABLES;
-- 在订阅端查看已同步的序列
SELECT * FROM pg_subscription;
6.2 不重启启用逻辑复制
-- PG19 之前:需要设置 wal_level = logical 并重启
-- PG19:按需启用,无需重启
-- 查看当前 effective WAL 级别
SHOW effective_wal_level; -- 可能显示 'logical'
6.3 postgres_fdw 查询联邦增强
-- 数组操作下推到远程服务器
SELECT * FROM remote_users
WHERE tags && ARRAY['admin', 'moderator'];
-- 获取远程表统计信息用于本地查询计划
ANALYZE remote_users; -- 自动从远程获取统计信息
七、监控与可观测性增强
7.1 pg_stat_lock:锁统计视图
-- 查看各锁类型的统计信息
SELECT locktype,
mode,
granted,
count
FROM pg_stat_lock;
7.2 pg_stat_recovery:恢复状态监控
-- 查看恢复操作的详细状态
SELECT * FROM pg_stat_recovery;
7.3 EXPLAIN ANALYZE 增强
-- PG19 EXPLAIN ANALYZE 现在可以显示 AIO 统计信息
EXPLAIN (ANALYZE, BUFFERS, IO)
SELECT * FROM large_table WHERE status = 'active';
八、安全增强
8.1 SNI 多证书(已在 5.4 节详述)
8.2 密码过期预警
-- 配置密码过期提前 7 天警告
ALTER SYSTEM SET password_expiration_warning_threshold = '7 days';
-- 客户端连接时会收到警告
-- WARNING: Your password will expire in 5 days
8.3 MD5 认证警告
-- PG19 对 MD5 认证发出警告(MD5 已被标记为不安全)
-- 建议迁移到 SCRAM-SHA-256
ALTER SYSTEM SET md5_password_warnings = on;
九、升级建议与注意事项
9.1 JIT 默认关闭的影响
如果你的系统依赖 JIT 加速复杂查询,升级后需要手动启用:
ALTER SYSTEM SET jit = on;
ALTER SYSTEM SET jit_above_cost = 100000;
9.2 lz4 压缩迁移
现有使用 pglz 压缩的 TOAST 数据不会自动转换。需要手动处理:
-- 对现有表启用 lz4 压缩
ALTER TABLE big_table ALTER COLUMN json_data SET COMPRESSION lz4;
-- 然后 VACUUM FULL 或 REPACK 触发重压缩
9.3 RADIUS 认证移除
PG19 移除了 RADIUS 认证支持,需要迁移到其他认证方式。
9.4 测试建议
Beta 版本不建议在生产环境使用,但强烈建议:
- 在测试环境用真实数据量和查询模式进行验证
- 重点关注 SQL/PGQ 的查询性能
- 验证并行 VACUUM 在你的工作负载下的效果
- 测试 pg_plan_advice 是否能稳定关键查询的执行计划
十、总结:PostgreSQL 19 的战略意义
PG19 不仅仅是一次常规的大版本更新,它标志着 PostgreSQL 从「关系型数据库」向「通用数据平台」的战略转型:
- SQL/PGQ 让 PG 成为图数据库的「替代方案」:对于 90% 的简单图查询场景,不再需要引入 Neo4j 等专用图数据库
- 并行 VACUUM + REPACK 解决了 PG 最大的运维痛点:大表维护不再是噩梦
- pg_plan_advice 让执行计划可控:消除了生产环境最大的不确定性来源
- WAIT FOR LSN + 逻辑复制增强:读写分离和数据同步变得更加简单可靠
PostgreSQL 三十而立,PG19 证明了它依然是全球最先进的开源关系型数据库。