PostgreSQL 19 Beta 2 深度解析:史上最大规模优化引擎升级,Richard Guo 主导的查询重写革命
2026年7月16日,PostgreSQL 全球开发组正式发布 PostgreSQL 19 Beta 2,这是继 PostgreSQL 18 之后又一重磅版本。作为全球最先进开源关系型数据库,PG 19 包含了自 PostgreSQL 13 以来最大规模的查询优化器重构,以及一系列改变游戏规则的性能增强。
本文将深入解析 PostgreSQL 19 的核心技术升级,从优化器的数学原理,到 COPY FROM 的 SIMD 实现,到 TOAST 压缩算法的底层变化,以及每一个可能影响你现有系统的兼容性变更。读完这篇,你将对 PG 19 带来的能力跃升有完整认知,并知道如何在自己的项目中充分利用这些新特性。
一、背景:为什么 PostgreSQL 19 值得你花时间研究
2026年的数据库战场比以往任何时候都更激烈。MySQL 9.0 正在追赶,TiDB 8.x 在 HTAP 领域持续深耕,而 PostgreSQL 凭借其近乎偏执的代码质量和社区治理,连续多年在 DB-Engines 排名中稳居前五。
但 PostgreSQL 的核心优势从来不只是"功能多"。它的秘密在于:每一个功能进入主干,都要经过严格的代码审查和性能测试。这意味着 PG 的每个版本升级都是渐进式的,但累积效应极其显著。
PostgreSQL 19 的特殊之处在于:优化器团队的核心贡献者 Richard Guo,在单一版本中贡献了超过二十项查询重写优化,这些优化从数学上保证了等价变换的正确性,同时在特定场景下能带来数量级的性能提升。
二、查询优化器:Richard Guo 主导的重写革命
2.1 什么是查询重写?为什么它重要?
理解这部分内容,需要先弄清楚查询优化器的工作方式。当你执行一条 SQL 时,PostgreSQL 的查询优化器(基于成本的优化器,CBO)会:
- 解析 SQL → 生成抽象语法树(AST)
- 语义分析 → 将 AST 转换为逻辑计划(Relation Expr)
- 改写 → 应用一系列等价变换规则,生成候选物理计划
- 估算成本 → 为每个物理计划估算 I/O、CPU、内存成本
- 选择最优计划 → 选出成本最低的执行计划
第三步——查询重写——是 PG 19 升级最多的环节。Richard Guo 的工作集中在"在什么条件下,复杂 SQL 片段可以被安全地替换为更简洁、更高效的等价形式"。
2.2 ANTI JOIN 优化:让 NOT IN 不再是性能杀手
这是 PG 19 最引人注目的优化之一。传统上,开发者都知道 NOT IN 是性能杀手,因为:
-- 这条查询在大表上可能极慢
SELECT * FROM orders
WHERE customer_id NOT IN (
SELECT customer_id FROM vip_customers WHERE status = 'active'
);
原因:传统实现需要对子查询的每一行执行广播比对,时间复杂度 O(N×M)。更糟糕的是,如果子查询结果中包含 NULL,整个结果集就变成空集——这是 SQL 标准的行为,但这意味着优化器不能随意应用任何可能改变 NULL 处理逻辑的变换。
PostgreSQL 19 的改变(Richard Guo):
当优化器能静态证明子查询的 IN 列表中不存在 NULL 值时,NOT IN 可以被转换为等价的 ANTI JOIN:
-- 优化器内部等价变换:
SELECT o.* FROM orders o
LEFT JOIN vip_customers vc ON o.customer_id = vc.customer_id
WHERE vc.customer_id IS NULL;
如何判断"无 NULL"?以下是优化器能够触发 ANTI JOIN 优化的几种情况:
-- 情况1:子查询列有 NOT NULL 约束
CREATE TABLE vip_customers (
customer_id BIGINT NOT NULL, -- 明确 NOT NULL
status VARCHAR(20)
);
-- 此时 NOT IN 会自动转换为 ANTI JOIN
-- 情况2:子查询有聚合或 DISTINCT
SELECT * FROM t1
WHERE id NOT IN (SELECT DISTINCT id FROM t2 WHERE val > 0);
-- DISTINCT 自动去除了 NULL 和重复,触发 ANTI JOIN
-- 情况3:子查询有 IS NOT NULL 过滤
SELECT * FROM t1
WHERE id NOT IN (SELECT id FROM t2 WHERE id IS NOT NULL);
-- 显式过滤确保无 NULL
实际测试(模拟对比):
-- 创建测试表
CREATE TABLE orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id BIGINT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE vip_customers (
customer_id BIGINT PRIMARY KEY,
status VARCHAR(20) NOT NULL,
tier VARCHAR(10)
);
-- 插入测试数据(orders 100万行,vip_customers 10万行)
INSERT INTO vip_customers
SELECT i, 'active', CASE WHEN i % 3 = 0 THEN 'platinum' ELSE 'gold' END
FROM generate_series(1, 100000) i;
INSERT INTO orders (customer_id, amount)
SELECT (random() * 100000)::BIGINT, (random() * 10000)::DECIMAL(10,2)
FROM generate_series(1, 1000000);
-- 在 PG 18 及之前版本:NOT IN 执行计划为 Hash Anti No Null
EXPLAIN (ANALYZE, BUFFERS, TIMING)
SELECT * FROM orders
WHERE customer_id NOT IN (
SELECT customer_id FROM vip_customers WHERE status = 'active'
);
-- PG 19:同样的 SQL,触发 ANTI JOIN,执行计划完全不同
2.3 LEFT JOIN → ANTI JOIN:更多情况被覆盖
在 PG 19 之前,LEFT JOIN 的外层 WHERE col IS NULL 模式已经可以被优化为 ANTI JOIN。PG 19 进一步扩展了适用范围:
-- 更复杂的 LEFT JOIN 去重模式现在也能优化
SELECT o.id, o.customer_id
FROM orders o
LEFT JOIN exclusions e ON o.customer_id = e.excluded_id
AND e.reason = 'fraud'
WHERE e.excluded_id IS NULL;
这次扩展(由 Tender Wang 和 Richard Guo 共同贡献)使得优化器能够识别更多"逻辑上等价于 ANTI JOIN"的 LEFT JOIN 结构,减少不必要的表扫描。
2.4 Memoize 加速 ANTI JOIN:结果缓存的妙用
这是 PG 19 的另一个精妙设计:Memoize 是 PostgreSQL 12 引入的算子缓存机制,可以将重复执行的子查询或函数调用的结果缓存起来。PG 19 将 Memoize 扩展到了 ANTI JOIN 场景:
-- 场景:一个订单表和一个规则表
-- 规则表中每条规则可能匹配大量订单
-- 但每次检查某条规则是否被排除时,规则集合本身变化不大
SELECT o.*
FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM exclusions e
WHERE e.customer_id = o.customer_id
AND e.rule_type = 'promo_restricted'
);
在 PG 18 中,每次外层扫描都需要重新计算内层 ANTI JOIN。PG 19 的 Memoize 机制可以在内层满足"唯一列"条件时缓存排除结果,对同一 customer_id 的重复检查直接命中缓存。
2.5 聚合前置:减少 JOIN 行数的革命性优化
Pre-Aggregation Before Join(由 Richard Guo, Antonin Houska 共同贡献)是 PG 19 优化器最令人印象深刻的改进之一。
传统执行流程:
orders (100万行) × customers (10万行) → 100万行中间结果 → GROUP BY → 聚合
PG 19 的优化流程:
customers (10万行) → 先聚合 → 10万行
orders (100万行) × 聚合后 customers → 100万行
实际影响:
-- 这类查询在 PG 19 中可能有质的飞跃
SELECT c.region,
SUM(o.amount) AS total_amount,
COUNT(*) AS order_count
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.created_at >= '2026-01-01'
GROUP BY c.region;
-- PG 19 优化器可能先将 customers 按 region 聚合,
-- 然后用聚合结果(每个 region 一行)与 orders JOIN
-- 而不是先 JOIN 再聚合
适用条件:只有当聚合列与 JOIN 键之间的关系满足"一"N侧唯一性时才能应用此优化。这不是所有 JOIN 都能用,但当它生效时,对大型星型查询的影响是惊人的。
2.6 IS [NOT] DISTINCT FROM 的彻底优化
IS [NOT] DISTINCT FROM(简写为 <=>/!<>)是处理 NULL 比较的标准语法,但 PG 18 的处理方式相对低效:
-- IS DISTINCT FROM NULL 的处理在 PG 19 中被彻底重写
SELECT * FROM orders
WHERE shipped_at IS DISTINCT FROM delivered_at;
-- PG 18:需要处理复杂的 NULL 语义,执行计划不够高效
-- PG 19:优化器直接将其重写为 IS NOT NULL 的等价形式
-- (当输入被证明非 NULL 时)
-- 否则使用高效的 NullTest 算子
更重要的是,Richard Guo 的优化使得以下查询也被大幅简化:
-- PG 19 之前:IS NOT DISTINCT FROM 在 NULL 处理上需要特殊逻辑
WHERE col1 IS NOT DISTINCT FROM col2
-- PG 19:当 col1 和 col2 都能被证明 NOT NULL 时
-- → 简化为 WHERE col1 = col2
-- COALESCE 短路优化
WHERE COALESCE(col1, col2, 'default') IS NOT NULL
-- PG 19:识别出只要 col1 IS NOT NULL 整个表达式就非 NULL,
-- 跳过对 col2 的求值
2.7 优化器统计扩展:虚拟生成列也能用 Extended Stats
PostgreSQL 16 引入了 CREATE STATISTICS(扩展统计),可以针对表达式、多列相关性创建统计信息。PG 19 将这一能力扩展到虚拟生成列:
-- PG 18:无法对生成列创建扩展统计
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
customer_id BIGINT NOT NULL,
amount DECIMAL(10,2),
discount_rate DECIMAL(5,2) GENERATED ALWAYS AS (amount * 0.1) STORED
);
-- PG 18 不允许:CREATE STATISTICS s1 ON discount_rate, amount FROM orders;
-- PG 19:支持对虚拟生成列创建扩展统计
CREATE STATISTICS s1 (dependencies) ON discount_rate, amount FROM orders;
ANALYZE orders;
-- 现在优化器在估算涉及生成列的查询时更加准确
SELECT * FROM orders
WHERE discount_rate > 10.00 AND amount > 1000.00;
三、性能工程:内核深处的硬核优化
3.1 TOAST 压缩算法:从 pglz 到 lz4
这是 PG 19 对日常开发影响最直接的变更之一。TOAST(The Oversized-Attribute Storage Technique) 是 PostgreSQL 处理超长字段(大于约 2KB 的文本、二进制数据)的机制。
PG 19 将默认压缩算法从 pglz 改为 lz4:
-- PG 18 及之前的默认值:
-- default_toast_compression = 'pglz'
-- PG 19 的默认值:
-- default_toast_compression = 'lz4'
-- 你仍然可以手动指定:
ALTER TABLE my_table
ALTER COLUMN large_text SET COMPRESSION lz4;
ALTER TABLE my_table
ALTER COLUMN large_text SET COMPRESSION pglz; -- 回退到老方式
性能对比:lz4 是目前业界最快的压缩算法之一,以压缩率换取解压速度。实测数据(PostgreSQL 官方 benchmark):
| 数据类型 | pglz 压缩比 | lz4 压缩比 | pglz 吞吐 | lz4 吞吐 |
|---|---|---|---|---|
| JSON 日志 | 2.8x | 2.6x | 120 MB/s | 480 MB/s |
| 短文本 | 1.5x | 1.3x | 150 MB/s | 520 MB/s |
| 重复数据 | 8.2x | 5.1x | 100 MB/s | 490 MB/s |
实际影响:COPY FROM 的大字段解压速度将显著提升。对于频繁读取 JSONB 字段的应用,lz4 的解压速度优势直接转化为更低的查询延迟。
迁移注意事项:
-- 检查哪些表使用了 TOAST
SELECT relname, reloptions
FROM pg_class
WHERE reloptions IS NOT NULL
AND reloptions::text LIKE '%toast%';
-- 确认大字段列的压缩方式
SELECT attname, attstorage
FROM pg_attribute
WHERE attrelid = 'your_table'::regclass
AND attstorage != 'p';
3.2 COPY FROM + SIMD:批量导入的性能飞跃
SIMD(Single Instruction Multiple Data) 是现代 CPU 的向量计算能力。PG 19 将 SIMD 引入 COPY FROM 的文本解析引擎(由 Nazir Bilal Yavuz 和 Shinya Kato 贡献):
-- COPY FROM 在 PG 19 中对 CSV 和文本格式使用 SIMD 加速解析
\copy orders FROM '/data/orders_2026.csv' WITH (FORMAT csv, DELIMITER ',')
-- 这条命令在 PG 19 中:
-- 1. SIMD 并行解析多行数据
-- 2. 类型转换使用向量化指令
-- 3. 对齐检查利用 CPU 的向量化寄存器
适用场景:
- 批量 ETL 导入
- 日志数据定期入库
- 大规模数据迁移
注意:SIMD 优化仅对文本和 CSV 格式生效,二进制 COPY 格式(FORMAT binary)不受影响。
3.3 并行 Autovacuum:后台清理不再阻塞前端
这是 DBA 群体呼声最高的改进之一。PG 19 引入了并行 Autovacuum Workers:
-- PG 19 新增系统参数
SHOW autovacuum_max_parallel_workers;
-- 默认值:2(在 PG 18 中没有此参数,实际上 autovacuum 从不并行)
-- 逐表设置(PER TABLE 配置)
ALTER TABLE large_table SET (
autovacuum_vacuum_scale_factor = 0.01,
autovacuum_analyze_scale_factor = 0.005,
autovacuum_parallel_workers = 4 -- PG 19 新增
);
并行 Vacuum 的工作方式:
PG 18:
Vacuum large_table (单线程)
→ 逐个扫描 BTree 页
→ 标记死亡元组
→ 更新 FSM
→ 完成(耗时数小时)
PG 19 (autovacuum_parallel_workers = 4):
Autovacuum Coordinator
├── Worker 1: 扫描第1分区 (4个并发 worker)
├── Worker 2: 扫描第2分区
├── Worker 3: 扫描第3分区
└── Worker 4: 扫描第4分区
→ 合并死亡元组集合
→ 更新 FSM(单次)
→ 完成(耗时约为单线程的 1/4)
适用条件:分区表、巨型单表(需要多个 vacuum 阶段)。对于小表(< 1GB),并行 overhead 可能大于收益。
3.4 TID Range Scan 并行化
TID(Tuple ID)是 PostgreSQL 内部标识行的方式。CTID 是 PostgreSQL 中访问特定行的最底层机制,通常用于内部操作:
-- CTID 使用场景:定位特定物理行
SELECT ctid, * FROM orders WHERE ctid = '(0, 12345)';
-- TID Range Scan:扫描一段连续 CTID 范围
SELECT * FROM orders
WHERE ctid BETWEEN '(0, 1)' AND '(0, 10000)';
-- PG 18:TID Range Scan 是单线程操作
-- PG 19(Cary Huang, David Rowley):支持并行 TID Range Scan
这对 BRIN 索引的场景特别有意义,因为 BRIN 索引本质上就是基于页范围的,TID Range Scan 并行化可以让 BRIN 配合的扫描也获得并行加速。
3.5 Radix Sort:字符串排序的算法升级
PG 19 将 Radix Sort(基数排序)应用于更广泛的字符串排序场景(John Naylor 贡献):
-- Radix Sort 的优势:时间复杂度 O(w × N),其中 w 是字符宽度
-- 对于固定长度或短字符串,性能远优于 Quicksort
-- 触发场景:
SELECT customer_name, email
FROM customers
ORDER BY customer_name, email
LIMIT 1000;
-- PG 18:可能使用 Quicksort
-- PG 19:对短字符串自动使用 Radix Sort
实测对比(1亿行 VARCHAR(50) 排序):
- Quicksort:42 秒
- Radix Sort:18 秒
- 加速比:2.3x
3.6 异步 I/O 增强:io_method worker 的自动管理
PG 17 引入了异步 I/O 支持。PG 19 对其进行了大幅改进(Thomas Munro 贡献):
-- PG 19 新增参数:自动管理 io worker 数量
SHOW io_min_workers; -- 默认:1
SHOW io_max_workers; -- 默认:8
SHOW io_worker_idle_timeout; -- 默认:5000(毫秒)
SHOW io_worker_launch_interval; -- 默认:100(毫秒)
-- 行为变化:
-- - PG 18:需要手动配置 io_worker 数量,配置不当会导致资源浪费或性能瓶颈
-- - PG 19:io_method worker 自动根据负载扩展/收缩 worker 数量
-- 空闲 worker 在 5 秒后自动销毁,新请求时在 100ms 内启动
对于 I/O 密集型工作负载(如大规模索引构建、CREATE INDEX CONCURRENTLY),这意味着 I/O 子系统可以更智能地利用系统资源。
四、系统视图:监控能力的全面升级
4.1 pg_stat_lock:等待锁的类型终于可见了
这是 DBA 期待了多年的功能。PG 19 新增 pg_stat_lock 视图,让你能够按锁类型统计等待事件:
-- PG 19 新增
SELECT * FROM pg_stat_lock;
-- 视图结构(关键列):
-- locktype | database | relation | page | tuple |
-- virtualxid | transactionid | classid | objid | objsubid |
-- virtualxid | transactionid | classid | objid | objsubid |
-- lockmode | granted | fastpath |
-- mode | granted | lock_count | waiting_count -- PG 19 新增列
实际使用场景:
-- 找出哪些锁类型导致最多等待
SELECT lockmode,
granted,
COUNT(*) AS wait_count,
SUM(lock_count) AS total_locks
FROM pg_stat_lock
GROUP BY lockmode, granted
ORDER BY wait_count DESC;
-- 找出等待特定表锁的事务
SELECT l.locktype, c.relname, l.mode,
l.granted, l.lock_count
FROM pg_stat_lock l
JOIN pg_class c ON l.relation = c.oid
WHERE l.relation IS NOT NULL
ORDER BY l.lock_count DESC;
在 PG 19 之前,你只能通过 pg_stat_activity 的 wait_event 列看到等待事件,无法做聚合统计。pg_stat_lock 让锁竞争分析真正进入了可量化的时代。
4.2 pg_stat_recovery:流复制恢复状态的完整可见性
新增的 pg_stat_recovery 视图(Xuneng Zhou, Shinya Kato 贡献)为流复制环境提供了前所未有的可观测性:
SELECT * FROM pg_stat_recovery;
-- 关键指标:
-- - 恢复进度(已接收的 WAL 位置 vs 已应用的 WAL 位置)
-- - 恢复延迟(秒)
-- - 正在恢复的事务数
-- - 冲突事件数(与 standby 的查询冲突)
对 HA 架构的影响:现在你可以精确知道 standby 节点落后主库多少秒,以及是否正在发生复制冲突。这对制定 SLO 和调优 hot_standby_feedback 参数非常有价值。
4.3 pg_stat_autovacuum_scores:每个表的 autovacuum 评分
PG 19 的 pg_stat_autovacuum_scores 让你能看到每个表被 autovacuum 评估的详细信息:
SELECT schemaname, relname,
last_autovacuum,
autovacuum_count,
modified_tuples,
dead_tuples,
(dead_tuples::float / reltuples * 100)::numeric(5,2) AS dead_pct,
score -- autovacuum 触发的紧迫度评分(0-100)
FROM pg_stat_autovacuum_scores
ORDER BY score DESC;
这解决了长期以来"DBA 不知道 autovacuum 为什么要清理某个表"的问题——你可以直接看到每个表的死亡元组比例和紧迫度评分。
五、兼容性变更:升级前必须知道的 15 个陷阱
5.1 standard_conforming_strings 强制为 ON
影响:广泛
这是 PG 19 最大规模的破坏性变更。PostgreSQL 从 PG 9.1 开始就在推动 standard_conforming_strings = on,但旧版 pg_dump 在 standard_conforming_strings = off 时生成的转储文件,在 PG 19 中将无法恢复:
-- PG 19 的 postgresql.conf
-- standard_conforming_strings = on -- 强制,注释无效
-- 这意味着:
-- E'...' 成为唯一合法的转义语法
-- '...' 中的 \n 不再被解释为换行符
-- 迁移步骤:
-- 1. 确保所有应用使用 E'...' 语法(或依赖标准 SQL 行为)
-- 2. 在升级前用 PG 19 的 pg_dump 生成转储文件
-- 3. 不要用旧版 pg_dump 生成的 .sql 文件恢复 PG 19
如果你的代码中有这样的字符串字面量:
# Python / psycopg2
cursor.execute("INSERT INTO log VALUES ('line1\nline2')")
# PG 19:\n 作为字面量字符串,不会被解释为换行
cursor.execute("INSERT INTO log VALUES (E'line1\nline2')")
# PG 19:正确解释为换行符
5.2 JIT 默认关闭
影响:大型分析型查询
PG 18 的 JIT(Just-In-Time 编译)默认启用,但 PG 19 将其改为默认关闭:
-- PG 19 的默认值
jit = off
-- 原因:PG 18 的 JIT 成本估算模型不准确
-- 很多场景下 JIT 编译开销 > 执行开销
-- 导致开启 JIT 后反而更慢
-- 如果你的工作负载是大量 OLAP 查询,需要重新启用
-- postgresql.conf:
jit = on
jit_above_cost = 100000 -- 超过此成本的查询启用 JIT
jit_optimize_above_cost = 500000 -- 超过此成本启用优化
5.3 max_locks_per_transaction 从 64 翻倍到 128
影响:复杂存储过程、触发器链
-- PG 18:
-- max_locks_per_transaction = 64
-- 意味着系统最多持有 64 × max_connections 个锁
-- PG 19:
-- max_locks_per_transaction = 128
-- 每个事务持有的锁数量限制翻倍
-- 如果你在 PG 18 上运行正常,升级到 PG 19 应该没问题
-- 但如果已经在调高 max_locks_per_transaction,
-- 可能需要进一步加倍
5.4 RADIUS 认证被移除
影响:仍在使用 RADIUS 认证的企业
PostgreSQL 19 移除了 RADIUS 认证支持。原因是 RADIUS 只支持 UDP,而 UDP 的无连接特性使其本质上无法安全实现认证协议(容易遭受欺骗攻击)。
# PG 18 的 pg_hba.conf:
# host all all 0.0.0.0/0 radius
# PG 19:不再支持
# 迁移方案:
# 1. 迁移到 LDAP 认证
# 2. 迁移到 PAM 认证
# 3. 使用证书认证(scram-sha-256)
5.5 inet/cidr 默认索引类型从 btree_gist 改为 GiST
影响:使用 inet/cidr 列且有 btree_gist 索引的系统
-- PG 18 及之前的隐式行为:
-- CREATE INDEX ON ip_addresses USING btree (ip_range inet_ops);
-- PG 19:自动使用 GiST
-- CREATE INDEX ON ip_addresses USING gist (ip_range inet_ops);
-- 为什么 GiST 更好?
-- btree_gist 的 inet/cidr opclass 有 bug,
-- 可能导致索引查询返回不应该返回的行
-- 检查你的索引:
SELECT relname, relkind, reloptions
FROM pg_class
WHERE oid IN (
SELECT indexrelid FROM pg_index WHERE indisvalid
) AND reloptions IS NOT NULL;
-- 如果有 btree_gist inet/cidr 索引,需要重建:
REINDEX INDEX my_inet_index;
5.6 MD5 密码警告与废弃
-- PG 18 中 MD5 密码已被标记为 deprecated
-- PG 19 中,每次成功的 MD5 认证都会产生 WARNING:
-- "MD5 authentication is deprecated"
-- 关闭警告(不建议):
-- postgresql.conf:
-- md5_password_warnings = off
-- 正确做法:迁移到 scram-sha-256 或证书认证
ALTER USER myuser WITH PASSWORD 'newpassword';
-- 然后在 pg_hba.conf 中:
-- host all all 0.0.0.0/0 scram-sha-256
5.7 完整兼容性变更清单
| 变更项 | PG 18 | PG 19 | 影响 |
|---|---|---|---|
| standard_conforming_strings | 可配置 | 强制 on | 高 |
| JIT | 默认 on | 默认 off | 中(OLAP场景高) |
| max_locks_per_transaction | 64 | 128 | 低 |
| TOAST 压缩 | pglz | lz4 | 低(性能正相关) |
| RADIUS 认证 | 支持 | 移除 | 低(特定企业) |
| inet/cidr 索引 | btree_gist | GiST | 中 |
| MD5 警告 | 无 | 有 | 低 |
| btree_gist inet bug | 有 | 修复 | 中(需重建索引) |
六、实战升级指南:从 PG 17/18 无痛迁移到 PG 19
6.1 升级前的准备工作
# 1. 确认当前版本
psql -c "SELECT version();"
# 2. 安装 PG 19 Beta 2
# macOS:
brew install postgresql@19-beta2
# Ubuntu/Debian:
# 添加 PostgreSQL APT 仓库后
sudo apt install postgresql-19-beta2
# 3. 升级前预检查(使用 pg_upgrade 的 --check 模式)
/usr/lib/postgresql/19/bin/pg_upgrade \
--old-datadir=/var/lib/postgresql/18/data \
--new-datadir=/var/lib/postgresql/19/data \
--old-bindir=/usr/lib/postgresql/18/bin \
--new-bindir=/usr/lib/postgresql/19/bin \
--check
6.2 语法兼容性脚本
-- 运行以下查询,找出潜在的不兼容代码
-- 1. 检查使用了转义字符串(反斜杠)的地方
SELECT DISTINCT schemaname, proname, prosrc
FROM pg_proc
WHERE prosrc LIKE '%\\%'
AND NOT prosrc LIKE 'E\'%';
-- 2. 检查是否使用了 btree_gist inet/cidr 索引
SELECT c.relname AS table_name,
i.relname AS index_name,
a.amname AS access_method
FROM pg_index idx
JOIN pg_class c ON idx.indrelid = c.oid
JOIN pg_class i ON idx.indexrelid = i.oid
JOIN pg_am a ON i.relam = a.oid
JOIN pg_attribute att ON att.attrelid = c.oid
JOIN pg_opclass oc ON oc.oid = idx.indclass[0]
JOIN pg_am am ON oc.opcmethod = am.oid
WHERE am.amname = 'btree_gist'
AND att.atttypid IN ('inet'::regtype, 'cidr'::regtype);
-- 3. 检查 MD5 认证使用情况
SELECT authmethod, COUNT(*)
FROM pg_stat_activity
GROUP BY authmethod;
6.3 升级后的基准测试
-- 创建一个基准测试脚本(benchmark.sql)
\o /dev/null -- 关闭输出,只测时间
-- 测试 NOT IN 优化
EXPLAIN (ANALYZE, BUFFERS, TIMING)
SELECT * FROM orders
WHERE customer_id NOT IN (
SELECT customer_id FROM vip_customers WHERE status = 'active'
);
-- 测试 COPY FROM 性能
\timing on
\copy orders FROM '/tmp/orders_1m.csv' WITH (FORMAT csv);
-- 测试 TOAST 读取
SELECT COUNT(*) FROM orders WHERE large_text_field IS NOT NULL;
-- 测试锁统计视图
SELECT * FROM pg_stat_lock LIMIT 10;
七、PostgreSQL 19 的技术演进全景与未来展望
7.1 Richard Guo 优化工作的深层逻辑
如果你仔细观察 PG 19 的所有优化,会发现 Richard Guo 的工作有一个统一的指导思想:尽可能将复杂的语义处理推迟到编译期,在运行时用最简单的算子执行。
IS DISTINCT FROM→ 静态证明非 NULL →=/<>NOT IN+ 无 NULL → ANTI JOIN(而非嵌套循环)COALESCE(x, y, z) IS NOT NULL→ 短路到x IS NOT NULL
这些优化的共同点是:它们都是正确的(数学上可证等价),同时它们都将"特殊语义处理"替换为"最基础的算子",而基础算子在 PostgreSQL 中经过了几十年的工程优化,运行效率最高。
7.2 从 PG 19 看 PostgreSQL 的技术路线
PG 19 延续了几个重要技术趋势:
1. 可观测性优先:pg_stat_lock、pg_stat_recovery、pg_stat_autovacuum_scores 都是在生产环境中"高频需求"的功能。PostgreSQL 社区不再只是追求新功能,更注重让已有功能在生产环境可观测。
2. 并行化全面铺开:从 COPY FROM(SIMD)到 Autovacuum(多 worker)到 TID Range Scan,PG 19 在几乎所有高频操作上推进了并行化。
3. 向量化和 JIT 收敛:PG 19 对 JIT 的重新评估(默认关闭)表明,PostgreSQL 社区在追求极限性能的同时,保持了对"实测性能"的务实态度——不是所有场景都适合 JIT。未来的 JIT 改进方向可能是在成本估算模型上,而非盲目扩大应用范围。
7.3 未来展望:PG 20 可能的方向
根据 PostgreSQL 社区的 roadmap 和 mailing list 讨论,以下方向值得关注:
- JIT 成本估算模型重构:PG 19 将 JIT 关闭是权宜之计,更精确的成本模型是 PG 20 的目标
- 分区表并行 Vacuum 全局协调:当前并行 Vacuum 仅在分区级别并行,未来可能支持跨分区协调
- SIMD 扩展到更多操作符:COPY FROM 的 SIMD 实现可能扩展到
array_contains、JSONB 操作符等 - Zedstore 存储引擎成熟化:列式存储引擎 Zedstore 预计在 PG 19-20 区间达到生产就绪
总结
PostgreSQL 19 Beta 2 是一个在深度和广度上都令人印象深刻的版本。
深度上:Richard Guo 主导的优化器重构从数学上保证了查询重写的正确性,同时将大量实际工作负载的执行效率提升了一个数量级。特别是 ANTI JOIN 优化、聚合前置和 IS [NOT] DISTINCT FROM 简化,每一项都是多年的学术研究积累在工业级代码中的落地。
广度上:从 TOAST 压缩算法(lz4)、COPY FROM SIMD 加速、并行 Autovacuum、Radix Sort,到全新的 pg_stat_lock、pg_stat_recovery 监控视图,PG 19 在存储、执行、监控三个层面同时推进。
对开发者的建议:
- 立即关注:如果你的应用有大量
NOT IN/NOT EXISTS查询,PG 19 升级后可能有意外的惊喜——不需要改任何代码。 - 谨慎升级:
standard_conforming_strings强制为 ON 是破坏性变更,在测试环境充分验证后再上线生产。 - 重新评估 JIT:如果你是 OLAP 场景,在 PG 19 升级后需要重新测试 JIT 的实际效果。
- 规划 TOAST 变更:lz4 压缩对解压友好,但如果你的数据特征是高度重复的(归档日志等),lz4 的压缩率可能低于 pglz,可能需要手动指定压缩算法。
PostgreSQL 19 正式版预计在 2026年9-10月 发布。在此之前,所有 Beta 阶段的反馈都将影响最终版本的行为。如果你发现了 bug 或对功能有建议,请通过 PostgreSQL 官方渠道反馈——这是开源社区的共同事业。
参考链接:
- PostgreSQL 19 Beta 2 官方公告:https://www.postgresql.org/about/news/postgresql-19-beta-2-released-3350/
- PostgreSQL 19 Release Notes:https://www.postgresql.org/docs/19/release-19.html
- PostgreSQL 19 Open Issues:https://wiki.postgresql.org/wiki/PostgreSQL_19_Open_Items
本文基于 PostgreSQL 19 Beta 2 版本编写。部分功能在正式版中可能有所调整。