编程 PostgreSQL 19 Beta 2 深度解析:史上最大规模优化引擎升级,Richard Guo 主导的查询重写革命

2026-07-24 16:15:36 +0800 CST views 7

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)会:

  1. 解析 SQL → 生成抽象语法树(AST)
  2. 语义分析 → 将 AST 转换为逻辑计划(Relation Expr)
  3. 改写 → 应用一系列等价变换规则,生成候选物理计划
  4. 估算成本 → 为每个物理计划估算 I/O、CPU、内存成本
  5. 选择最优计划 → 选出成本最低的执行计划

第三步——查询重写——是 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.8x2.6x120 MB/s480 MB/s
短文本1.5x1.3x150 MB/s520 MB/s
重复数据8.2x5.1x100 MB/s490 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_activitywait_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 18PG 19影响
standard_conforming_strings可配置强制 on
JIT默认 on默认 off中(OLAP场景高)
max_locks_per_transaction64128
TOAST 压缩pglzlz4低(性能正相关)
RADIUS 认证支持移除低(特定企业)
inet/cidr 索引btree_gistGiST
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_containsJSONB 操作符
  • 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_lockpg_stat_recovery 监控视图,PG 19 在存储、执行、监控三个层面同时推进。

对开发者的建议

  1. 立即关注:如果你的应用有大量 NOT IN/NOT EXISTS 查询,PG 19 升级后可能有意外的惊喜——不需要改任何代码。
  2. 谨慎升级standard_conforming_strings 强制为 ON 是破坏性变更,在测试环境充分验证后再上线生产。
  3. 重新评估 JIT:如果你是 OLAP 场景,在 PG 19 升级后需要重新测试 JIT 的实际效果。
  4. 规划 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 版本编写。部分功能在正式版中可能有所调整。

推荐文章

MySQL 优化利剑 EXPLAIN
2024-11-19 00:43:21 +0800 CST
Grid布局的简洁性和高效性
2024-11-18 03:48:02 +0800 CST
rangeSlider进度条滑块
2024-11-19 06:49:50 +0800 CST
MySQL设置和开启慢查询
2024-11-19 03:09:43 +0800 CST
程序员茄子在线接单