PG 19 默认关掉 JIT:用 pg_stat_statements 找出以前替它承担成本的查询
PostgreSQL 19 已经到 RC 1,GA 计划在 2026 年 11 月 19 日。这个版本里 jit 的默认值从 PostgreSQL 18 的 on 变成 off。
改这个行为的 commit 由 Jelte Fennema-Nio 撰写、Tomas Vondra 在 2026 年 4 月 2 日 push,原话是:有时看似无关的改动(比如往表里多插几行)会把成本推得刚好够开 JIT,“resulting in a performance cliff”。同一段说明还提到,大部分大规模部署早就把 JIT 关了,“Notably, this includes all hyperscalers”。发布说明的措辞也很直接:JIT 基于成本的触发“has been determined to be unreliable”,这项改动“requires sites that are doing many large analytical queries to manually enable JIT”。
所以升级前要准备两张名单:JIT 一直在拖慢的查询,升级后自动变快;JIT 一直在帮忙的查询,不处理就变慢。两张名单都躺在现有库里。
JIT 在做什么,旧默认怎么决定开不开
Postgres 的 JIT 通过 LLVM 把查询的一部分编译成本地代码。按文档,目前加速两件事:表达式求值(WHERE、target list、聚合、投影)和 tuple deforming,也就是把磁盘上的行转成内存里的形态。只有服务器用 --with-llvm 编译过,这套东西才存在。
开不开是在计划阶段定的,拿查询的总估算成本和三个阈值比,阈值在 query planning 的配置项里:
jit_above_cost,默认100000:决定是否编译。jit_inline_above_cost,默认500000:决定是否内联小函数和操作符。jit_optimize_above_cost,默认500000:决定是否跑那套昂贵的 LLVM 优化。
这三个阈值在 19 里一个数都没变。变的是 jit 本身,从 18 的 on 变成 off。阈值只在你重新打开 JIT 之后才有意义。
旧默认的行为可以概括成一句话:跨过成本线就付编译成本,不管这条查询到底需不需要。
读 EXPLAIN ANALYZE 里的 JIT 块
在 EXPLAIN ANALYZE 输出里找 JIT 那一段,它给出编译各阶段的耗时和总编译时间。把这段编译开销和查询实际执行时间放在一起看:编译时间占比高、执行时间省得少,这条查询在 18 上就是被 JIT 拖着的。这也是升级后能免费变快的那一批。
检查设置、修改配置,注意生效范围
先跑:
SHOW jit;
commit 里说得很清楚,多数大规模部署(含 hyperscalers)本来就把 JIT 关了。如果你的实例报 off,19 在这一点上没有任何变化,可以直接跳到文末其它默认值。
要改的话,这些设置只对新会话生效,所以得回收连接池;SET ROLE 不会重新加载角色设置,只有真正登录一次才行。改完确认会话最终拿到了什么:
SHOW jit;
SELECT pg_jit_available();
pg_jit_available() 只有在 JIT provider 已安装且 jit 为 on 时才返回 true,所以它也能顺带发现服务器是不是编译时没带 LLVM。三个成本阈值保持默认,除非你自己的 benchmark 给出了移动它们的理由。
只给需要 JIT 的角色开:
ALTER ROLE SET jit = on;
想全局改也可以,但记得这是给所有会话的:
ALTER SYSTEM SET jit = on;
SELECT pg_reload_conf();
同一版本里一起变的其它默认值
max_locks_per_transaction从 64 变成 128。发布说明提到锁大小的分配方式改了,所以“effectively settings must now be doubled to match their capacity in previous releases”。原来在 18 上调到 256 的,19 上的等效值是 512。这个参数只能在服务器启动时设置。- TOAST 压缩默认从 pglz 变成 lz4,通过
default_toast_compression控制。前提是服务器编译时带了--with-lz4,否则仍然是 pglz。列上自己的COMPRESSION选项依旧覆盖默认值。 log_lock_waits默认开启。任何会话等锁超过deadlock_timeout(默认 1s)就会写一行日志。锁竞争重的系统要预期日志量上升;以前从没开过这个参数的话,这是一个新的可用信号。
能悄悄把查询延迟往两个方向推的,是 JIT 这一项。这周就把 pg_stat_statements 拉一遍:按总执行时间排序,看排在前面的那些查询的形状——短事务的 OLTP 和高成本的分析型查询分成两堆,后者就是“JIT 可能在帮忙”的那一桶,重点 benchmark 桶顶部的几条。ALTER ROLE 的语句在 11 月 19 日之前写好,而不是等第一块变慢的看板出现之后再补。
谁会受影响,该怎么处理
来自 neon.com 的 PostgreSQL 19 breaking changes 页面:
JIT Compilation Disabled by Default
jit参数现在默认是 off。从 PostgreSQL 12 起 JIT 默认开启,但经验表明它给短的 OLTP 查询增加延迟,对多数负载没有实质收益。
-- 查看当前设置
SHOW jit;
-- 如果你的负载确实受益,再打开
ALTER SYSTEM SET jit = on;
SELECT pg_reload_conf();
受影响的人:跑分析型 / OLAP 负载,查询复杂、有大顺序扫描、聚合重的,升级后可能看到回归,这类负载是真正从 JIT 编译里拿到收益的。跑典型 OLTP(短查询、每秒大量事务)的,大概率没有变化,反而因为省掉 JIT 开销略有改善。
要做的事:升级前把最重要的那些查询在 jit = on 和 jit = off 下各测一遍。JIT 有帮助,就在 postgresql.conf 里显式写上 jit = on;拿不准就保持关闭,那是更安全的默认值。