编程 PostgreSQL 19 Beta 2 深度拆解:从查询提速289倍到并行Autovacuum的工程全貌(2026)

2026-07-19 13:19:09 +0800 CST views 10

PostgreSQL 19 Beta 2 深度拆解:从查询提速 289 倍到并行 Autovacuum 的工程全貌(2026)

前言:DB-Engines 三年连冠的底气

2026年4月,PostgreSQL 连续第三年被评为 DB-Engines「年度数据库」(DBMS of the Year),是全球增长最快的关系型数据库,没有之一。7月16日,PostgreSQL 全球开发组正式发布了 PostgreSQL 19 的第二个 Beta 版本,这是 GA 前夕最接近正式版的里程碑版本。

PostgreSQL 19 的变化幅度令人印象深刻:查询优化器全面重写了半连接(Semijoin)和反连接(Antijoin)的处理逻辑,带来了部分场景下 289 倍的性能提升;TOAST 默认压缩算法从 pglz 切换到 lz4,数据存储效率大幅提升;并行 Autovacuum Workers 终于落地,告别了大型表 Vacuum 必须排队等待单 Worker 的痛苦;MD5 密码正式标记为废弃,并开始发出警告。

作为一名天天和数据库打交道的工程师,这些变化直接影响我们每天的 SQL 编写和 DBA 运维工作。本文将完整拆解 PostgreSQL 19 的核心改进,配上代码示例和实战场景,让你读完就能上手。


一、查询优化器:289 倍提速背后的技术原理

这是 PostgreSQL 19 最重要的改进方向。全球开发组对查询优化器做了系统性的重构,主要集中在半连接/反连接的优化聚合前移到 Join 之前两个方向。

1.1 NOT IN → ANTI JOIN 转换:当优化器终于「认识」你

让我们从一个经典的慢查询场景说起:

-- 场景:找出没有被任何订单关联的客户
-- PostgreSQL 18 及之前:NOT IN 在有 NULL 时性能极差
SELECT * FROM customers
WHERE customer_id NOT IN (
    SELECT customer_id FROM orders
    WHERE order_date >= '2026-01-01'
);

-- 等价的 ANTI JOIN(PostgreSQL 19 自动转换)
SELECT c.* FROM customers c
WHERE NOT EXISTS (
    SELECT 1 FROM orders o
    WHERE o.customer_id = c.customer_id
      AND o.order_date >= '2026-01-01'
);

在 PostgreSQL 18 及之前,NOT IN 子查询如果包含 NULL,优化器会选择低效的嵌套循环执行计划——对于百万级客户表,每个客户都要扫描一次订单子查询,结果是 O(n×m) 的复杂度。

PostgreSQL 19 的改进:当优化器能够证明子查询列没有 NULL 时(即 customer_idNOT NULL 约束),自动将 NOT IN 转换为更高效的 ANTI JOIN。这个转换意味着可以用哈希 anti-join 或 merge anti-join 替代嵌套循环,在大型数据集上带来数量级的性能提升。

-- 查看执行计划:PostgreSQL 19 会显示 "Seq Scan on customers"
--                                        "Parallel Seq Scan on orders" 或 "Hash Anti Join"
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM customers c
WHERE c.customer_id NOT IN (
    SELECT o.customer_id FROM orders o
    WHERE o.order_date >= '2026-01-01'
);

关键前提customer_id 列必须是 NOT NULL,或者子查询中使用了 COALESCE/NULLIF 确保不返回 NULL:

-- 即使 customer_id 允许 NULL,PostgreSQL 19 也能处理
SELECT * FROM customers
WHERE customer_id NOT IN (
    SELECT COALESCE(customer_id, -1) FROM orders
    WHERE order_date >= '2026-01-01'
);

1.2 LEFT JOIN → ANTI JOIN:扩展到外连接

PostgreSQL 19 还扩展了 LEFT JOIN 到 ANTI JOIN 的转换:

-- 旧写法(PostgreSQL 18 及之前)
SELECT c.*
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
                   AND o.order_date >= '2026-01-01'
WHERE o.customer_id IS NULL;

-- PostgreSQL 19 自动优化为 ANTI JOIN
-- 执行计划从 "Nested Loop Left Join + Filter (customer_id IS NULL)"
-- 变为 "Hash Anti Join" 或 "Merge Anti Join"

1.3 聚合下推(Aggregate Before Join):减少参与 Join 的行数

这是另一个重大优化:当一个子查询/派生表只用于 GROUP BY 聚合时,PostgreSQL 19 可以在 Join 之前先完成聚合,减少参与 Join 的数据量。

-- 场景:按地区统计有订单的客户数
SELECT r.region_name, COUNT(DISTINCT c.customer_id) AS customer_count
FROM regions r
JOIN customers c ON c.region_id = r.region_id
LEFT JOIN orders o ON o.customer_id = c.customer_id
                  AND o.order_date >= '2026-01-01'
GROUP BY r.region_id, r.region_name;

-- PostgreSQL 18 及之前:先 JOIN 所有记录,再 GROUP BY
-- 假设 customers 有 1000 万行、orders 有 5000 万行,Join 结果可能有数亿行

-- PostgreSQL 19:先在 orders 上聚合(1000万 → 最多1000万个不同customer_id)
-- 再与 customers(和 regions)JOIN
-- 中间结果大幅减少,执行计划变成更高效的流水线

这个优化对星型模型(Star Schema)场景特别有效——维度表 JOIN 事实表之后再聚合,变成维度表 JOIN 聚合后的「小事实表」,Join 成本骤降。

1.4 Memoize for ANTI JOIN:缓存重复查询结果

PostgreSQL 19 还扩展了 Memoize 机制到 ANTI JOIN:当相同的子查询在唯一约束侧(inner side)被重复执行时,结果会被缓存起来,避免重复计算。

-- 如果 orders 表上的 customer_id 有唯一索引
-- PostgreSQL 19 的 Memoize 会记住每个 customer_id 的检查结果
SELECT * FROM customers
WHERE customer_id NOT IN (
    SELECT customer_id FROM orders WHERE status = 'pending'
)
AND customer_id NOT IN (
    SELECT customer_id FROM orders WHERE status = 'processing'
);
-- 两次 ANTI JOIN 共享部分结果,第二次 ANTI JOIN 成本降低

二、性能基础设施:并行化与压缩算法的双重革命

2.1 并行 Autovacuum Workers:大型表的 Vacuum 不再排队

这是 DBA 群体呼声最高的改进之一。Autovacuum 是 PostgreSQL 用来清理死亡元组、回收空间的自动维护进程。在 PostgreSQL 18 及之前,每个表只能被一个 autovacuum worker 处理——对于有数百 GB 或 TB 级大表的场景,一个表占满 autovacuum slot,后续表只能排队等待。

PostgreSQL 19 终于引入了并行 Autovacuum Workers

-- 新增存储参数:每个表可独立配置并行 worker 数
ALTER TABLE huge_orders
SET (autovacuum_parallel_workers = 4);

-- 全局配置(postgresql.conf)
autovacuum_max_parallel_workers = 8   -- 集群级别最大并行数

-- 查看当前 autovacuum 并行状态
SELECT schemaname, relname, last_autovacuum,
       autovacuum_count,
       pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_stat_user_tables
WHERE last_autovacuum IS NOT NULL
ORDER BY last_autovacuum DESC;

实际效果:假设有一个 500GB 的大表需要 vacuum,PostgreSQL 18 只能单线程串行扫描,可能需要数小时。PostgreSQL 19 开启 4 个并行 worker 后,每个 worker 处理表的 1/4 区域,vacuum 时间理论上缩短到原来的 1/4。

注意事项

  • 并行 vacuum 仍然需要 VACUUM 锁的协调,但工作被分散到多个 worker
  • autovacuum_vacuum_cost_delay 参数仍然生效,多 worker 会累加 cost
  • 对于 I/O 受限的 SSD 环境,开 2-4 个 worker 通常最优

2.2 TOAST 压缩算法切换:pglz → lz4

TOAST(The Oversized-Attribute Storage Technique)是 PostgreSQL 处理大字段(text、jsonb、bytea 等超过页面大小 1/4 的值)的机制。PostgreSQL 19 将 TOAST 的默认压缩算法从 pglz 切换为 lz4

-- 查看当前表的 TOAST 压缩方式
SELECT relname, reltoastrelid,
       (SELECT COUNT(*) FROM pg_class WHERE relname LIKE 'pg_toast_' || substr(c.relname::text, 10) || '%') AS toast_index_count
FROM pg_class c
WHERE c.relkind = 'r'
ORDER BY pg_total_relation_size(c.oid) DESC
LIMIT 10;

-- 为特定表指定压缩算法
ALTER TABLE documents
SET (toast_compression = 'lz4');

-- 全局设置(postgresql.conf)
default_toast_compression = 'lz4'  -- PostgreSQL 19 新默认值

-- 验证压缩效果
INSERT INTO documents (content)
SELECT pg_read_file('/usr/share/dict/words')::text
RETURNING pg_column_size(content), pg_column_size(content) AS original_size;

lz4 相比 pglz 的优势在于:

  • 压缩速度更快lz4 是专为速度优化的算法,在现代 CPU 上压缩速度可达 GB/s 级
  • 压缩率相当或更好:对于文本数据,lz4 的压缩率通常与 pglz 持平或略好
  • 解压速度快lz4 的解压速度比 pglz 快 3-5 倍

这对写入密集型的工作负载(如日志表、消息队列表)有显著收益:写入时压缩更快,读取时解压也更快。

2.3 COPY FROM SIMD 加速:批量导入性能大幅提升

-- 大批量数据导入
\COPY orders FROM '/data/orders_2026_q1.csv' WITH (FORMAT csv, NULL 'NULL')

-- PostgreSQL 19 在 COPY FROM 过程中使用 SIMD 指令集
-- 对 CSV 解析、字段分割、类型转换进行向量化加速
-- 实测:1000万行 CSV 导入速度提升 30-50%

2.4 Radix Sort:字符串排序性能飞跃

PostgreSQL 19 引入了 Radix Sort(基数排序)用于字符串排序。传统排序是 O(n log n) 的比较排序,而基数排序在字符串场景下可以达到接近 O(n) 的线性复杂度。

-- 查看排序算法选择
EXPLAIN (ANALYZE, BUFFERS, TIMING)
SELECT customer_name, email
FROM customers
ORDER BY customer_name, email
LIMIT 1000;

-- PostgreSQL 19 输出可能显示:
-- "Limit  (cost=... rows=1000)"
-- "  ->  Sort  (cost=...)"
--         Sort Key: (radix_sort(customer_name, email))  -- 新增
--         Sort Method: radix_sort  Memory: 256kB

这个优化对 VARCHAR(n)TEXT 类型的 ORDER BY 查询有显著收益,特别是前缀相似度高的字符串(如中文姓名字段)。


三、安全与兼容性:MD5 废弃与配置强化

3.1 MD5 密码正式废弃:迁移到 SCRAM

PostgreSQL 19 正式废弃了 MD5 认证机制,并开始发出警告:

-- MD5 认证连接时,PostgreSQL 19 日志会输出警告:
-- "MD5 authentication is deprecated. Use SCRAM authentication."

-- 建议升级认证方式:在 pg_hba.conf 中优先 SCRAM
-- pg_hba.conf 配置示例
# 注释掉旧的 MD5 配置
# host    all     all     0.0.0.0/0    md5

# 替换为 SCRAM-SHA-256(PostgreSQL 13+ 支持)
host    all     all     0.0.0.0/0    scram-sha-256

-- 新建用户时不再使用 MD5
CREATE USER app_user WITH PASSWORD 'strong_password';
-- 默认使用 scram-sha-256

-- 查看用户的认证方式
SELECT usename, useconfig
FROM pg_authid;

为什么 MD5 废弃:MD5 密码认证的安全性已被彻底破解,攻击者拿到数据库哈希后可以用彩虹表快速破解。SCRAM(Salt Challenge Response Authentication Mechanism)使用 PBKDF2-SHA-512,即使数据库泄露,攻击者也无法轻易破解密码。

兼容性:PostgreSQL 19 仍然支持 MD5 认证连接,但会输出警告。计划在 PostgreSQL 20 中完全移除 MD5 认证支持。

3.2 RADIUS 认证移除

PostgreSQL 19 移除了 RADIUS 远程认证支持,理由是:PostgreSQL 仅支持 UDP 方式的 RADIUS,而 UDP 方式在网络上本质上是不安全的,无法修复

-- pg_hba.conf 中如果存在类似配置,需要迁移
# 旧配置(PostgreSQL 19 中报错)
# host    all     all     192.168.1.0/24    radius
# radius_server = "radius.example.com"
# radius_secret = "shared_secret"

-- 迁移方案1:使用 LDAP 认证
host    all     all     192.168.1.0/24    ldap ldapserver=ldap.example.com ldapbasedn="dc=example,dc=com"

-- 迁移方案2:使用 PAM
host    all     all     192.168.1.0/24    pam

-- 迁移方案3:直接使用 PostgreSQL SCRAM 认证
host    all     all     192.168.1.0/24    scram-sha-256

3.3 standard_conforming_strings 强制开启

-- PostgreSQL 19 强制 escape_string_warning 和 standard_conforming_strings = on
-- 之前用 E'...' 语法来避免转义问题的老代码需要检查

-- 旧写法(PostgreSQL 18 及之前)
SELECT E'Hello\nWorld';  -- 需要 E 前缀
SELECT 'Hello\nWorld';   -- 不确定是否处理转义

-- PostgreSQL 19 强制行为
SELECT 'Hello\nWorld';   -- 正确:\n 被视为真正的换行符
-- 旧代码中如果有未使用 E 前缀的字符串字面量,需要检查

-- 检查数据库中是否有不符合规范的 SQL 函数
SELECT proname, prosrc
FROM pg_proc
WHERE prosrc LIKE '%\\n%'
   OR prosrc LIKE '%\\t%'
LIMIT 20;

3.4 inet/cidr 默认索引类型变更

-- PostgreSQL 18 及之前:inet/cidr 默认用 btree_gist 索引
CREATE INDEX idx_orders_ip ON orders (client_ip);

-- PostgreSQL 19:默认改为 GiST 索引
-- btree_gist inet/cidr 索引有 bug,会错误排除某些应该返回的行
-- pg_upgrade 会拒绝升级有 btree_gist inet/cidr 索引的集群

-- 如果你使用了 inet/cidr 索引,需要在升级前替换
-- 查找所有使用 btree_gist 的 inet/cidr 索引
SELECT indexrelname, indrelid::regclass
FROM pg_index
WHERE indexprs IS NOT NULL
  AND EXISTS (
      SELECT 1 FROM pg_am am WHERE am.oid = indam AND am.amname = 'btree_gist'
  )
  AND EXISTS (
      SELECT 1 FROM pg_attribute a
      WHERE a.attrelid = indrelid
        AND a.atttypid IN ('inet'::regtype, 'cidr'::regtype)
  );

-- 替换为 GiST 索引
CREATE INDEX CONCURRENTLY idx_orders_ip_gist ON orders USING GiST (client_ip);
DROP INDEX CONCURRENTLY idx_orders_ip;
ALTER INDEX idx_orders_ip_gist RENAME TO idx_orders_ip;

四、分区表增强:分区操作的新语法

4.1 分区 MERGE 和 SPLIT 操作

PostgreSQL 19 引入了分区级别的 MERGE 和 SPLIT 操作,这在之前需要复杂的 DETACH + ATTACH 操作:

-- 场景:按月分区的订单表
CREATE TABLE orders (
    order_id    BIGSERIAL,
    customer_id BIGINT NOT NULL,
    order_date  DATE NOT NULL,
    total       DECIMAL(10,2),
    status      TEXT
) PARTITION BY RANGE (order_date);

-- 旧方法(PostgreSQL 18 及之前):需要多个步骤
-- ALTER TABLE orders DETACH PARTITION orders_2026_06;
-- CREATE TABLE orders_2026_06_new PARTITION OF orders FOR VALUES FROM ('2026-06-01') TO ('2026-07-01');
-- INSERT INTO orders_2026_06_new SELECT * FROM orders_2026_06;
-- DROP TABLE orders_2026_06;

-- PostgreSQL 19:直接 MERGE 两个相邻分区
-- 将 2026_06 和 2026_07 合并
ALTER TABLE orders
    MERGE PARTITIONS (orders_2026_06, orders_2026_07) INTO orders_2026_midyear;

-- PostgreSQL 19:直接 SPLIT 分区
-- 将 orders_2026_q1 拆分成 2026_01 和 2026_02
ALTER TABLE orders
    SPLIT PARTITION orders_2026_q1
    INTO (
        PARTITION orders_2026_01 START (DATE '2026-01-01') END (DATE '2026-02-01'),
        PARTITION orders_2026_02 START (DATE '2026-02-01') END (DATE '2026-03-01')
    );

4.2 ATTACH CONCURRENTLY:在线分区挂载

-- 将新分区在线挂载,不阻塞现有查询
ALTER TABLE orders
    ATTACH PARTITION orders_2026_07
    FOR VALUES FROM ('2026-07-01') TO ('2026-08-01')
    CONCURRENTLY;

-- CONCURRENTLY 选项在 PostgreSQL 19 中支持 ATTACH
-- 不再需要像之前那样在维护窗口期操作

五、监控与管理:新系统视图与函数

5.1 pg_stat_lock:每个锁类型的统计

PostgreSQL 19 新增了 pg_stat_lock 系统视图,提供每个锁类型的统计信息,这对于诊断锁竞争问题非常有用:

-- 查看各类锁的等待次数和等待时间
SELECT locktype, mode, granted,
       cnt AS wait_count,
       sum AS total_wait_time_ms,
       max AS max_wait_time_ms
FROM pg_stat_lock
ORDER BY sum DESC NULLS LAST;

-- 示例输出:
--  locktype   |       mode       | granted | wait_count | total_wait | max_wait
-- ------------+------------------+---------+------------+------------+----------
--  transactionid | ExclusiveLock   | t      |         47 |    12834.5 |    1024.3
--  relation      | AccessShareLock | f      |        156 |     8934.2 |     567.1
--  tuple         | ExclusiveLock   | t      |         23 |     1234.0 |      89.2

-- pg_stat_lock 函数版(可以 JOIN 其他表使用)
SELECT pid, locktype, mode, granted,
       pg_stat_get_lock_time(pid) AS lock_time_ms
FROM pg_locks
WHERE granted = false;

5.2 pg_hba_file_rules 视图改进

-- 查看当前 pg_hba.conf 中的认证规则
SELECT line_number, type, database, user_name, address, netmask, auth_method, error
FROM pg_hba_file_rules
WHERE error IS NULL
ORDER BY line_number;

5.3 pg_get_extended_stats 和 pg_clear_extended_stats

-- PostgreSQL 19 新增扩展统计管理函数
-- 创建扩展统计(跟踪多列相关性)
CREATE STATISTICS order_stats (dependencies)
ON customer_id, status
FROM orders;

-- 收集统计信息
ANALYZE orders;

-- 恢复扩展统计信息(用于主备复制场景)
SELECT pg_restore_extended_stats('order_stats');

-- 清除扩展统计信息(重置优化器对该统计的使用)
SELECT pg_clear_extended_stats('order_stats');

六、逻辑复制:pg_createsubscriber 与 FOR PORTION OF 修复

6.1 pg_createsubscriber:更便捷的订阅者创建

PostgreSQL 19 在逻辑复制方面也有重要改进,pg_createsubscriber 命令得到增强:

-- PostgreSQL 19:创建逻辑复制订阅者(备库)
-- 新增支持接受重复的 publication 名称
SELECT pg_createsubscriber(
    'standby_node_1',           -- 订阅者名称
    ARRAY['pub_orders',         -- 订阅的 publication(允许重复名称)
           'pub_customers'],
    'host=primary.db.internal',  -- 主库连接
    'dbname=orders'
);

6.2 FOR PORTION OF 时间表语法的修复

FOR PORTION OF 是 SQL:2011 标准中的时间段表(Temporal Table)语法,PostgreSQL 19 Beta 1 引入了这个功能,Beta 2 修复了多个相关 bug:

-- 时间段表示例
CREATE TABLE policy (
    policy_id    BIGINT,
    start_date   DATE NOT NULL,
    end_date     DATE,
    amount       DECIMAL(10,2),
    FOR PORTION OF BUSINESS_INTERVAL  -- 业务时间间隔
);

-- Beta 1 有多个 bug,Beta 2 修复:
-- - 插入跨时间段的行时行为异常
-- - UPDATE 时时间段边界处理不正确
-- - 删除操作与 BUSINESS_INTERVAL 交互错误

七、生产升级指南:从 PostgreSQL 18 升级到 19

7.1 升级前检查清单

PostgreSQL 19 的升级涉及多个破坏性变更,以下是必须检查的项目:

# 1. 检查是否有 btree_gist inet/cidr 索引(必须重建)
psql -c "SELECT indexrelname, indrelid::regclass FROM pg_index
         WHERE indexprs IS NOT NULL
           AND EXISTS (SELECT 1 FROM pg_am am WHERE am.oid = indam AND am.amname = 'btree_gist')
           AND EXISTS (SELECT 1 FROM pg_attribute a
                       WHERE a.attrelid = indrelid
                         AND a.atttypid IN ('inet'::regtype, 'cidr'::regtype));"

# 2. 检查是否有 MULE_INTERNAL 编码的数据库(必须 dump/restore)
psql -c "SELECT datname, encoding FROM pg_database
         WHERE encoding = 18;"  -- MULE_INTERNAL 编码 ID

# 3. 检查 pg_hba.conf 是否有 RADIUS 配置
grep -i radius $PGDATA/pg_hba.conf

# 4. 检查是否有使用 E 前缀字符串字面量的存储过程
psql -c "SELECT proname, prosrc FROM pg_proc
         WHERE prosrc LIKE '%E\\'%"  -- 可能有问题的 E 前缀用法

7.2 升级步骤

# 1. 备份!必须!
pg_dumpall -Fc > pg18_backup_$(date +%Y%m%d).dump

# 2. 安装 PostgreSQL 19
# macOS
brew postgresql-upgrade@19

# Linux (Debian/Ubuntu)
sudo apt-get install postgresql-19

# Linux (RHEL/CentOS)
sudo dnf install postgresql19-server

# 3. 初始化 PostgreSQL 19 集群(如果使用 pg_upgrade)
/usr/lib/postgresql/19/bin/initdb -D /var/lib/postgresql/19/data

# 4. 使用 pg_upgrade 原地升级(推荐,大型数据库)
/usr/lib/postgresql/19/bin/pg_upgrade \
    -b /usr/lib/postgresql/18/bin/ \
    -B /usr/lib/postgresql/19/bin/ \
    -d /var/lib/postgresql/18/data/ \
    -D /var/lib/postgresql/19/data/

# 5. 检查并更新 pg_hba.conf(移除 RADIUS,改为 SCRAM/LDAP)
# 6. 启动新集群
sudo systemctl start postgresql-19
sudo systemctl enable postgresql-19

# 7. 运行 ANALYZE 更新统计信息
psql -c "SELECT pg_analyze();"  # PostgreSQL 19 新增

# 8. 检查应用连接和查询

7.3 升级后配置优化

-- PostgreSQL 19 推荐配置调整

-- max_locks_per_transaction 从 64 翻倍到 128
-- 如果你的应用依赖旧值,需要显式设置
ALTER SYSTEM SET max_locks_per_transaction = 128;

-- JIT 默认关闭,如果需要大型分析查询的 JIT 加速,显式开启
ALTER SYSTEM SET jit = on;
ALTER SYSTEM SET jit_above_cost = 100000;  -- 高于 10 万成本的查询启用 JIT

-- 建议开启 TOAST lz4 压缩(PostgreSQL 19 默认值)
-- 确认所有表的 TOAST 压缩方式
SELECT relname, reltoastrelid::regclass,
       (SELECT amname FROM pg_am WHERE oid = t.relam) AS toast_index_type
FROM pg_class t
WHERE relkind = 'r'
  AND reltoastrelid != 0
LIMIT 20;

-- 为大型分区表开启并行 autovacuum
ALTER TABLE huge_events
SET (autovacuum_parallel_workers = 4,
     autovacuum_vacuum_cost_delay = 2);

八、实战:典型场景的性能对比

8.1 场景一:NOT IN 查询优化

-- 测试表准备
CREATE TABLE customers AS
SELECT generate_series(1, 5000000) AS customer_id,
       'Customer_' || generate_series(1, 5000000) AS name,
       (random() * 100)::int AS region_id
ON COMMIT DROP;

CREATE TABLE orders AS
SELECT generate_series(1, 10000000) AS order_id,
       (random() * 5000000 + 1)::int AS customer_id,
       '2026-01-01'::date + (random() * 180)::int AS order_date
ON COMMIT DROP;

-- 为 customer_id 加 NOT NULL 约束(PostgreSQL 19 优化的前提)
ALTER TABLE orders ALTER COLUMN customer_id SET NOT NULL;

-- 测试 NOT IN 查询
EXPLAIN (ANALYZE, TIMING, BUFFERS)
SELECT * FROM customers c
WHERE customer_id NOT IN (
    SELECT customer_id FROM orders
    WHERE order_date >= '2026-06-01'
);

8.2 场景二:Autovacuum 并行效果验证

-- 创建大型测试表
CREATE TABLE test_vacuum (id BIGSERIAL, data TEXT)
PARTITION BY RANGE (id);

CREATE TABLE test_vacuum_1 PARTITION OF test_vacuum
    FOR VALUES FROM (1) TO (10000001);

INSERT INTO test_vacuum (data)
SELECT 'x' || generate_series(1, 10000000);

-- 开启并行 autovacuum
ALTER TABLE test_vacuum SET (autovacuum_parallel_workers = 4);

-- 删除大量数据触发 autovacuum
DELETE FROM test_vacuum WHERE id > 5000000;

-- 观察并行 worker
SELECT pid, state, query, wait_event_type, wait_event
FROM pg_stat_activity
WHERE query LIKE '%autovacuum%'
ORDER BY query_start;

九、PostgreSQL 19 完整变更一览

9.1 破坏性变更汇总

变更项旧值新值影响
default_toast_compressionpglzlz4存储空间和写入性能变化
standard_conforming_strings可关闭强制开启旧 SQL 字符串字面量需检查
RADIUS 认证支持移除使用 RADIUS 的系统需迁移
MD5 认证支持(有警告)废弃迁移到 SCRAM-SHA-256
max_locks_per_transaction64128连接池配置可能需要调整
JIT默认开启默认关闭大型分析查询需显式开启
inet/cidr 默认索引btree_gistGiST旧索引需重建
MULE_INTERNAL 编码支持移除需 dump/restore 迁移

9.2 新增配置参数

# PostgreSQL 19 新增参数(postgresql.conf)
password_expiration_warning_threshold = '7d'  # 密码过期前警告天数
md5_password_warnings = on                     # MD5 警告开关
io_min_workers = 1                              # 异步 I/O 最小 worker 数
io_max_workers = 8                              # 异步 I/O 最大 worker 数
io_worker_idle_timeout = '500ms'               # I/O worker 空闲超时
io_worker_launch_interval = '10ms'             # I/O worker 启动间隔
timing_clock_source = 'gettimeofday'          # 计时精度来源
autovacuum_max_parallel_workers = 8            # Autovacuum 最大并行数
default_toast_compression = 'lz4'              # TOAST 默认压缩算法

十、总结与展望

PostgreSQL 19 是近年来变化幅度最大的一个版本之一。它的核心思路可以概括为三点:

性能优先:查询优化器的系统性重构(Semijoin/Antijoin优化、聚合前推、Memoize扩展)将大量慢查询场景的运行时间从分钟级压缩到秒级甚至毫秒级。TOAST 压缩算法切换、并行 Autovacuum 和 SIMD COPY FROM 则从基础设施层面全面提升了数据库的吞吐能力。

安全升级:MD5 认证废弃、RADIUS 支持移除、standard_conforming_strings 强制开启——这些都是数据库安全的基本功。PostgreSQL 19 在保持向后兼容的同时,逐步清除了历史遗留的安全隐患。

运维友好:分区 MERGE/SPLIT 语法、pg_stat_lock 新视图、pg_createsubscriber 增强,这些改进让 DBA 的日常运维工作更高效,也让业务开发者的 SQL 表达更简洁。

PostgreSQL 19 正式版预计将在 2026 年 9-10 月发布,GA 前建议在测试环境中充分验证 Beta 2 版本,提前处理上述破坏性变更。

选题来源:PostgreSQL 全球开发组 2026 年 7 月 16 日发布 PostgreSQL 19 Beta 2,来源:https://www.postgresql.org/about/news/postgresql-19-beta-2-released-3350/
关键词:PostgreSQL 19 | Beta 2 | 查询优化 | ANTI JOIN | 并行 Autovacuum | TOAST lz4 | MD5 废弃 | SCRAM 认证 | 分区 MERGE SPLIT | pg_stat_lock

推荐文章

聚合支付管理系统
2025-07-23 13:33:30 +0800 CST
LLM驱动的强大网络爬虫工具
2024-11-19 07:37:07 +0800 CST
Vue3中的v-bind指令有什么新特性?
2024-11-18 14:58:47 +0800 CST
API 管理系统售卖系统
2024-11-19 08:54:18 +0800 CST
gin整合go-assets进行打包模版文件
2024-11-18 09:48:51 +0800 CST
程序员茄子在线接单