PostgreSQL JIT 詳細講解
PostgreSQL JIT 詳細講解
PostgreSQL 的 JIT(Just-In-Time Compilation)是 PostgreSQL 11 引入的一個高級性能優(yōu)化特性。
很多人會誤以為:
“開啟 JIT = SQL 自動變快”
實際上并不是。
在真實生產環(huán)境中:
- 有些系統(tǒng)開啟后性能提升明顯
- 有些系統(tǒng)開啟后 CPU 飆升、RT 變差
- 很多 Rails / API 系統(tǒng)最后會選擇關閉 JIT
所以理解 JIT 的核心,不是“怎么開啟”,而是:
它到底優(yōu)化什么、適用于什么場景、為什么會拖慢系統(tǒng)。
一、JIT 是什么?
JIT 全稱:
Just-In-Time Compilation(即時編譯)
本質上:
PostgreSQL 會把 SQL 執(zhí)行中的部分邏輯,動態(tài)編譯成機器碼執(zhí)行。
傳統(tǒng) PostgreSQL 的執(zhí)行方式
默認情況下,PostgreSQL 是:
SQL → Parser(解析) → Planner(生成執(zhí)行計劃) → Executor(執(zhí)行器) → Interpreter(逐行解釋執(zhí)行)
也就是說:
SQL 中的表達式:
price * tax_rate > 100
會被 PostgreSQL 一行一行解釋執(zhí)行。
每處理一行:
- 讀取字段
- 做運算
- 做判斷
- 返回結果
這種方式靈活,但 CPU 開銷較高。
二、JIT 的核心原理
JIT 會把這些“重復執(zhí)行的表達式邏輯”:
price * tax_rate > 100
編譯成:CPU 可以直接執(zhí)行的機器碼
從而:
- 減少解釋器開銷
- 減少函數(shù)調用
- 提升 CPU 執(zhí)行效率
三、JIT 解決什么問題?
JIT 主要解決的是:
“CPU 計算開銷過高”的問題
不是 IO 問題。
四、JIT 優(yōu)化的核心場景
JIT 主要優(yōu)化:
| 類型 | 示例 |
|---|---|
| 表達式計算 | CASE WHEN、數(shù)學運算 |
| JSONB 解析 | -> / ->> |
| WHERE 復雜過濾 | 多層條件 |
| 聚合計算 | SUM / COUNT / GROUP BY |
| 大量行處理 | Seq Scan / Bitmap Scan |
| CPU 密集型 SQL | 報表統(tǒng)計 |
五、JIT 不優(yōu)化什么?
JIT:
? 不優(yōu)化磁盤 IO
? 不優(yōu)化索引
? 不優(yōu)化網絡
? 不優(yōu)化鎖等待
? 不優(yōu)化慢 JOIN 算法
六、JIT 的真正優(yōu)化目標
JIT 優(yōu)化的是:
Executor 階段中的“表達式執(zhí)行成本”
即:每處理一行數(shù)據(jù)時的 CPU 成本
七、JIT 工作流程
PostgreSQL JIT 基于 LLVM。
工作流程:
SQL → Planner → Executor → LLVM IR → Machine Code → CPU 執(zhí)行
八、JIT 的幾個階段
EXPLAIN ANALYZE 中你會看到:
JIT:
Functions: 10
Options: Inlining true, Optimization true
Timing:
Generation 3.2 ms
Inlining 20 ms
Optimization 35 ms
Emission 10 ms1. Generation
生成 LLVM IR。
2. Inlining
函數(shù)內聯(lián)。
減少函數(shù)調用成本。
3. Optimization
LLVM 做代碼優(yōu)化。
4. Emission
生成機器碼。
九、為什么 JIT 有時候反而更慢?
JIT 的本質:編譯成本 + 執(zhí)行收益
如果:編譯時間 > 節(jié)省時間
那么:
JIT 就會拖慢 SQL
十、典型錯誤場景
? 小 SQL
SELECT * FROM users WHERE id = 1;
問題:
- SQL 執(zhí)行可能只要 1ms
- JIT 編譯可能花 5~20ms
結果:
總耗時變大
? 高頻 API SQL
Rails / GraphQL 系統(tǒng)非常常見:
SELECT * FROM tasks WHERE project_id = ? LIMIT 20;
特點:
- 高頻
- 短 SQL
- 延遲敏感
這種場景:
JIT 幾乎一定不劃算
? 高并發(fā)系統(tǒng)
JIT 會:
- 增加 CPU
- 增加 LLVM 編譯壓力
- 增加 latency spike
十一、哪些場景適合 JIT?
? 報表系統(tǒng)(OLAP)
例如:
SELECT
user_id,
SUM(price * tax_rate)
FROM orders
GROUP BY user_id;
特點:
- 掃描大量數(shù)據(jù)
- 計算復雜
- SQL 執(zhí)行時間長
? 大 JSONB 查詢
SELECT * FROM logs WHERE metadata->>'type' = 'error';
? 數(shù)據(jù)分析類 SQL
- 大聚合
- 大過濾
- CPU-heavy
十二、哪些場景不適合?
? OLTP
例如:
- Rails
- 微服務
- GraphQL
- API Server
特點:
- 查詢短
- QPS 高
- latency 敏感
? 索引查詢?yōu)橹?/h3>
WHERE id = ?
WHERE id = ?
這種本來就很快。
? 高并發(fā)在線業(yè)務
JIT 容易導致:
- CPU 波動
- RT 抖動
- p99 上升
十三、如何查看 JIT 是否生效?
查看是否開啟
SHOW jit;
查看 JIT 參數(shù)
SHOW jit_above_cost; SHOW jit_inline_above_cost; SHOW jit_optimize_above_cost;
十四、核心參數(shù)詳解
1. jit
是否開啟。
SET jit = on;
2. jit_above_cost(最重要)
表示:
查詢成本超過多少才啟用 JIT
默認通常較高。
避免小 SQL 被誤傷。
3. jit_inline_above_cost
是否啟用 inline。
4. jit_optimize_above_cost
是否啟用 LLVM 優(yōu)化。
十五、如何分析 JIT 問題?
最重要的方法:
1. EXPLAIN ANALYZE
EXPLAIN (ANALYZE, BUFFERS, JIT) SELECT ...
你會看到:
JIT:
Functions: 8
Timing:
Generation 4ms
Optimization 30ms
2. pg_stat_statements 統(tǒng)計 JIT 開銷(核心排查 SQL)
下面這條 SQL 可以用于:
- 找出正在使用 JIT 的 SQL
- 分析 JIT 平均耗時
- 判斷 JIT 是否值得
- 排查哪些 SQL 被 JIT “誤傷”
SELECT
query,
calls,
rows,
round((total_exec_time / calls)::numeric, 2) AS avg_exec_ms,
round((total_plan_time / calls)::numeric, 2) AS avg_plan_ms,
round(
(
(
jit_generation_time +
jit_inlining_time +
jit_optimization_time +
jit_emission_time
) / calls
)::numeric,
2
) AS avg_jit_ms,
round(
(
(
jit_generation_time +
jit_inlining_time +
jit_optimization_time +
jit_emission_time
) / NULLIF(total_exec_time, 0) * 100
)::numeric,
2
) AS jit_percent,
jit_functions,
round((shared_blks_hit::numeric / NULLIF(calls, 0)), 2) AS avg_buffer_hit,
round((shared_blks_read::numeric / NULLIF(calls, 0)), 2) AS avg_disk_read
FROM pg_stat_statements
WHERE jit_functions > 0
ORDER BY jit_percent DESC, avg_jit_ms DESC
LIMIT 20;
十六、如何解讀這條排查 SQL?
avg_exec_ms
total_exec_time / calls
平均執(zhí)行時間。
avg_jit_ms(核心)
( jit_generation_time + jit_inlining_time + jit_optimization_time + jit_emission_time ) / calls
表示:
每次 SQL 平均花多少時間在 JIT 編譯上
jit_percent(最關鍵指標)
jit_time / total_exec_time
表示:
SQL 總時間中,有多少比例浪費在 JIT 上
十七、如何判斷當前 SQL 不適合 JIT?
?? 情況 1:jit_percent > 20%
說明:
很多時間都浪費在 LLVM 編譯,而不是 SQL 執(zhí)行。
這是最典型的:
- API SQL
- Rails SQL
- GraphQL SQL
問題。
?? 情況 2:avg_jit_ms 很高
例如:
| 指標 | 值 |
|---|---|
| avg_exec_ms | 20ms |
| avg_jit_ms | 8ms |
說明:
40% 時間花在 JIT 上。
通常不劃算。
?? 情況 3:calls 非常高
例如:
| calls | avg_exec_ms |
|---|---|
| 100000 | 5ms |
這種高頻 SQL:
幾乎一定不適合 JIT
因為:
編譯成本根本無法攤銷。
?? 情況 4:IO 很低但 CPU 很高
例如:
avg_disk_read 很低 avg_buffer_hit 很低 但 avg_exec_ms 很高
說明:
問題不是 IO。
而是:
CPU 計算 + JIT 開銷
十八、生產環(huán)境最佳實踐
OLTP 系統(tǒng)(Rails / API)
通常建議:
jit = off
原因:
- latency 更穩(wěn)定
- CPU 更低
- p99 更好
OLAP / 報表系統(tǒng)
建議:
jit = on
因為:
- SQL 很長
- CPU-heavy
- 編譯成本可攤銷
十九、生產上最推薦的策略
不是:
全局開
也不是:
全局關
而是:
推薦方案
默認關閉
jit = off
報表 SQL 單獨開啟
SET LOCAL jit = on;
或提高觸發(fā)門檻
jit_above_cost = 100000
避免短 SQL 被 JIT。
二十、總結一句話
PostgreSQL JIT 是一個“用編譯換執(zhí)行速度”的 CPU 優(yōu)化器,只適合“大量數(shù)據(jù) + 復雜計算”的 SQL,不適合高頻短查詢 OLTP 系統(tǒng)。
二十一、你當前場景的判斷(結合你之前的問題)
你之前提到:
- 慢 SQL
- Rails
- GraphQL
- API
- CPU 壓力
- 懷疑 JIT 導致慢查詢
這種場景里:
關閉 JIT 是非常常見且合理的優(yōu)化方向。
因為:
你的系統(tǒng)更像:
OLTP / API 型系統(tǒng)
而不是:
OLAP / 報表型系統(tǒng)
所以:
jit = off
很可能會:
- 降低 CPU
- 提升 RT 穩(wěn)定性
- 降低 p99
- 減少 latency spike
到此這篇關于PostgreSQL JIT 詳細講解的文章就介紹到這了,更多相關PostgreSQL JIT內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
PostgreSQL流復制參數(shù)max_wal_senders的用法說明
這篇文章主要介紹了PostgreSQL流復制參數(shù)max_wal_senders的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
詳解如何優(yōu)化在PostgreSQL中對于日期范圍的查詢
在 PostgreSQL 中,處理日期范圍的查詢是常見的操作,然而,如果不進行適當?shù)膬?yōu)化,這些查詢可能會導致性能問題,特別是在處理大型數(shù)據(jù)集時,本文章將詳細討論如何優(yōu)化在 PostgreSQL 中對于日期范圍的查詢,需要的朋友可以參考下2024-07-07
PostgreSQL連接數(shù)過多的原因分析與連接池方案
在 PostgreSQL 的生產運維中,連接數(shù)過多是最常見且影響深遠的性能問題之一,本文將系統(tǒng)性地剖析 連接數(shù)過多的根本原因,詳解 PostgreSQL 連接機制與資源開銷,并對比主流 連接池方案的原理、配置與適用場景,需要的朋友可以參考下2026-02-02
Postgresql psql文件執(zhí)行與批處理多個sql文件操作
這篇文章主要介紹了Postgresql psql文件執(zhí)行與批處理多個sql文件操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
postgresql數(shù)據(jù)庫執(zhí)行計劃圖文詳解
了解PostgreSQL執(zhí)行計劃對于程序員來說是一項關鍵技能,執(zhí)行計劃是我們優(yōu)化查詢,驗證我們的優(yōu)化查詢是否確實按照我們期望的方式運行的重要方式,這篇文章主要給大家介紹了關于postgresql數(shù)據(jù)庫執(zhí)行計劃的相關資料,需要的朋友可以參考下2024-01-01
PostgreSQL 使用raise函數(shù)打印字符串
這篇文章主要介紹了PostgreSQL 使用raise函數(shù)打印字符串,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01

