版本选择建议(LTS / 最新版)
本节回答一个非常实际的问题:生产环境到底该用哪个 PostgreSQL 版本? 学完本节,你将理解 PostgreSQL 为什么没有传统意义的 LTS,并掌握一套可落地的选版与升级窗口规划方法。
前置知识
阅读本节前,建议先了解:PostgreSQL vs MySQL vs Oracle
基础概念
先澄清一个高频误解:PostgreSQL 社区不使用 "LTS" 这个说法。很多团队在选型文档里写"选 PostgreSQL 16 LTS",其实并不存在这样一个正式标记。
PostgreSQL 的策略是统一支持周期:每个主版本自首发日起获得 5 年官方支持,之后进入生命周期结束(EOL, End of Life)。由于每年发布一个大版本,任意时刻通常有 5 个左右主版本处于支持状态。这与"少数版本长期支持、其余短期支持"的 LTS 模式在机制上完全不同。
| 术语 | 含义 | 对选型的影响 |
|---|---|---|
| 主版本(Major Version) | 每年发布一次的大版本,如 16、17、18;含新功能,数据目录不兼容 | 决定你能用哪些特性,也决定升级成本 |
| 次要版本(Minor Version) | 每年约 4 次的小版本,如 18.1~18.6;只修 bug 与安全问题 | 无脑升级,必须跟随 |
| 支持周期(Support Lifecycle) | 主版本首发后 5 年 | 决定"最晚什么时候必须升" |
| EOL | 支持期结束,此后不再有安全补丁 | 生产环境不应停留在 EOL 版本 |
| 发布路线图(Roadmap) | 官方公布未来小版本的计划日期 | 用于规划维护窗口 |
| 前沿版 vs 成熟版 | 刚发布的大版本(前沿)与已发布 1~2 年的大版本(成熟) | 决定风险偏好 |
一句话总结选版原则:大版本可以慢一年,小版本必须快一个季度。
语法与用法
选版不是凭感觉,先把"当前状态"量化出来。以下查询在任何 PostgreSQL 实例上都能直接运行。
-- 1. 查看当前实例的完整版本与运行平台
SELECT version(); version
---------------------------------------------------------------------------------------------------------
PostgreSQL 18.6 on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
(1 row)-- 2. 结构化版本号,便于程序判断与巡检脚本告警
SELECT
current_setting('server_version') AS version, -- 如 18.6
current_setting('server_version_num') AS version_num, -- 如 180006
current_database() AS db_name; version | version_num | db_name
---------+-------------+---------
18.6 | 180006 | demo
(1 row)-- 3. 判断是否还在官方支持期内(按 5 年支持期粗略折算)
-- 维护一张版本 → EOL 日期的映射表比硬编码逻辑更可靠
WITH supported(version_num, eol_date) AS (
VALUES
(180000, DATE '2030-11-14'),
(170000, DATE '2029-11-08'),
(160000, DATE '2028-11-09'),
(150000, DATE '2027-11-11'),
(140000, DATE '2026-11-12')
)
SELECT
s.version_num,
s.eol_date,
(s.eol_date - CURRENT_DATE) AS days_left,
CASE
WHEN s.eol_date < CURRENT_DATE THEN '已 EOL,立即升级'
WHEN s.eol_date - CURRENT_DATE < 365 THEN '一年内 EOL,纳入升级计划'
ELSE '支持期内'
END AS advice
FROM supported AS s
WHERE s.version_num = (current_setting('server_version_num')::int / 10000) * 10000
ORDER BY s.eol_date; version_num | eol_date | days_left | advice
-------------+------------+-----------+-----------------
180000 | 2030-11-14 | 1515 | 支持期内
(1 row)# 4. 运维侧批量巡检:一次拿到所有集群的版本
pg_lsclustersVer Cluster Port Status Owner Data directory Log file
18 main 5432 online postgres /var/lib/postgresql/18/main /var/log/postgresql/postgresql-18-main.log
15 main 5433 online postgres /var/lib/postgresql/15/main /var/log/postgresql/postgresql-15-main.log# 5. 客户端工具版本应与服务端尽量一致(避免 pg_dump 版本过旧)
psql --version
pg_dump --version
pg_upgrade --version详细说明
为什么 PostgreSQL 没有传统 LTS
LTS(Long Term Support)模式的存在前提是"发布节奏不规律或支持成本需要分层"。Ubuntu、Node.js 之所以需要 LTS,是因为它们的版本发布频繁且支持层度需要区分。PostgreSQL 用另一种方式解决了同一个问题:
- 固定 5 年支持期,而不是"选几个版本给更长支持"。
- 每年一个大版本,节奏稳定,企业可以把它当作年度例行工作。
- 小版本滚动发布,只含修复,升级无需改代码、不需要 dump/restore。
- 主版本不兼容数据目录,所以"跨版本兼容"这件事本身就不成立,也就没必要用 LTS 来承诺它。
这带来的实践结论是:选"最新大版本减一"通常是最优解——既拿到了接近最新版本的能力与性能,又避开了新版本刚发布时的生态适配期。
各版本支持状态与推荐矩阵
下表按维护时间表整理(EOL 日期以官方 Versioning Policy 为准):
| 主版本 | 首次发布 | EOL | 定位 | 生产建议 |
|---|---|---|---|---|
| 18 | 2025-09 | 2030-11 | 最新稳定版 | 新项目首选;含 AIO、Skip Scan、uuidv7() 等改进 |
| 17 | 2024-09 | 2029-11 | 成熟稳定版 | 保守团队首选;生态适配最充分 |
| 16 | 2023-09 | 2028-11 | 成熟版 | 可用,但新项目不建议作为起点 |
| 15 | 2022-10 | 2027-11 | 即将进入后期 | 存量系统可维持,规划升级 |
| 14 | 2021-09 | 2026-11 | 临近 EOL | 一年内必须完成升级 |
| 13 及更早 | ≤2020 | 已 EOL | 停止维护 | 立即评估升级,存在安全风险 |
按业务场景的选择建议:
| 场景 | 推荐版本 | 理由 |
|---|---|---|
| 全新项目、无历史包袱 | 最新大版本(18) | 生命周期最长,可用新特性,避免上线即落后 |
| 全新项目、强合规要求 | 最新大版本减一(17) | 生态与文档更充分,第三方扩展兼容性验证更久 |
| 存量系统升级 | 目标锁定最新或减一 | 一次到位,避免两年内再升一次 |
| 依赖特定扩展(PostGIS / pgvector / TimescaleDB) | 先查扩展兼容矩阵再定版本 | 扩展对新版本的支持常滞后数周至数月 |
| 使用云托管服务 | 跟随云厂商可选版本 | 托管服务的可用版本列表通常滞后于社区 |
| 容器化部署 | 官方镜像的 -alpine / -bookworm 具体标签 | 避免使用 latest 标签导致不可控升级 |
小版本升级与主版本升级的区别
这两类升级的运维动作完全不同,必须区分对待:
| 维度 | 小版本升级(如 18.5 → 18.6) | 主版本升级(如 17 → 18) |
|---|---|---|
| 数据目录兼容性 | 完全兼容 | 不兼容,无法直接启动 |
| 是否需要迁移数据 | 不需要 | 需要(pg_upgrade / 逻辑复制 / dump-restore) |
| 停机时间 | 秒级 | 分钟到小时级 |
| 是否可能改 SQL 行为 | 理论上不改变 | 可能(废弃语法、默认值变化) |
| 回退难度 | 换回旧二进制即可 | 极难,需依赖备份 |
| 建议频率 | 跟随官方季度节奏 | 每 2~3 年一次,提前半年规划 |
-- 小版本升级前的安全检查:确认没有长事务阻塞关闭
SELECT pid, state, now() - xact_start AS xact_age, left(query, 60) AS query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start
LIMIT 10;-- 升级前确认没有活动的复制槽(未使用的槽会拖住 WAL 清理)
SELECT slot_name, slot_type, active, restart_lsn
FROM pg_replication_slots
WHERE NOT active;决定升级时机的信号
不要等到 EOL 才行动。以下任一信号出现,就应把升级列入当季计划:
- 距离当前版本 EOL 不足 12 个月。
- 需要的某个扩展只支持新版本(例如新版本 PostGIS)。
- 业务遇到了在新版本已被修复的性能或正确性问题。
- 遇到安全漏洞但没有对应小版本可用(说明已 EOL)。
- 云厂商明确通知该版本将下线。
- 需要新版本独有的能力,例如声明式分区增强、
MERGE、逻辑复制改进、向量索引性能。
版本与扩展的兼容性
版本选择的约束往往不在数据库本身,而在扩展。升级前必须先确认扩展是否支持目标版本。
-- 查看当前已安装的扩展及其版本
SELECT extname, extversion FROM pg_extension ORDER BY extname; extname | extversion
--------------+------------
pg_stat_statements | 1.11
pg_trgm | 1.6
plpgsql | 1.0
postgis | 3.5.0
(4 rows)-- 查看目标版本上有哪些扩展可用(需在目标版本实例中执行)
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE name IN ('postgis', 'pgvector', 'pg_trgm', 'timescaledb')
ORDER BY name; name | default_version | installed_version
-----------+-----------------+-------------------
pg_trgm | 1.6 | 1.6
pgvector | 0.8.0 |
postgis | 3.5.0 |
(3 rows)实战示例
场景:一套运行在 PostgreSQL 14.24 上的订单系统,数据量 800 GB,要求 2026 年内完成升级(14 将于 2026-11 EOL)。以下是完整的选版与升级决策过程。
第 1 步:确认现状
SELECT
current_setting('server_version') AS version,
current_setting('server_version_num') AS version_num,
pg_size_pretty(pg_database_size(current_database())) AS db_size; version | version_num | db_size
---------+-------------+---------
14.24 | 140024 | 812 GB
(1 row)第 2 步:清点依赖,判断能否直接跳到最新版
-- 已装扩展清单:任何一项不支持目标版本,都会阻塞升级
SELECT extname, extversion FROM pg_extension ORDER BY extname; extname | extversion
-------------------+------------
pg_stat_statements | 1.9
pg_trgm | 1.6
plpgsql | 1.0
(3 rows)-- 检查是否有已废弃语法依赖:以 text 上的 btree 排序差异为例
SELECT count(*) AS tables_with_text_index
FROM pg_index i
JOIN pg_class c ON c.oid = i.indrelid
JOIN pg_am am ON am.oid = i.indclass[0]
WHERE am.amname = 'btree'; tables_with_text_index
------------------------
37
(1 row)第 3 步:确定目标版本
结合本文矩阵:14 已临近 EOL,应一次跳到最新稳定版 18,避免两年内再升一次。
| 候选 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| 16 | 生态成熟 | 3 年后仍需升级 | 放弃 |
| 17 | 成熟且支持到 2029 | 2029 后仍需升级 | 备选 |
| 18 | 支持到 2030-11,生命周期最长 | 新版本,需验证扩展 | 采纳 |
第 4 步:在预发环境演练升级
# 4.1 用 pg_upgrade --check 做无副作用的预检
/usr/lib/postgresql/18/bin/pg_upgrade \
--old-datadir=/var/lib/postgresql/14/main \
--new-datadir=/var/lib/postgresql/18/main \
--old-bindir=/usr/lib/postgresql/14/bin \
--new-bindir=/usr/lib/postgresql/18/bin \
--checkPerforming Consistency Checks
-----------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for new cluster tablespace directories ok
*Clusters are compatible*# 4.2 预检通过后正式执行(--link 用硬链接缩短停机时间,--jobs 并行加速)
/usr/lib/postgresql/18/bin/pg_upgrade \
--old-datadir=/var/lib/postgresql/14/main \
--new-datadir=/var/lib/postgresql/18/main \
--old-bindir=/usr/lib/postgresql/14/bin \
--new-bindir=/usr/lib/postgresql/18/bin \
--link --jobs=4第 5 步:升级后重建统计信息并回归验证
-- 5.1 校验版本与数据完整性
SELECT current_setting('server_version') AS version;
SELECT count(*) AS order_count FROM orders;
SELECT sum(amount) AS total_amount FROM orders; version
---------
18.6
(1 row)
order_count | total_amount
-------------+--------------
428391 | 91538204.55
(1 row)-- 5.2 确认扩展在新版本下正常工作
SELECT extname, extversion FROM pg_extension ORDER BY extname;
SELECT similarity('机械键盘', '机械健盘') AS sim; -- pg_trgm 生效即返回非 0 extname | extversion
--------------+------------
pg_stat_statements | 2.1
pg_trgm | 1.6
plpgsql | 1.0
(3 rows)
sim
---------
0.666667
(1 row)# 5.3 收回旧版本的扩展与新集群统计信息
/usr/lib/postgresql/18/bin/vacuumdb --all --analyze-in-stages第 6 步:保留观察期
# 不要立即删除旧集群,保留 1~2 周以便问题回溯
# 确认无异常后,再回收 14 的数据目录与旧安装包
pg_lsclusters注意事项
- 不要把 "LTS" 写进技术方案。PostgreSQL 没有 LTS 标记,写"选了 LTS 版本"会让评审与后续维护产生误解。正确表述是"选择当前支持期最长的主版本"。
-- 错误!不存在这样的元数据,查询会报错
-- SELECT is_lts FROM pg_settings WHERE name = 'server_version';- 不要在主版本升级后继续使用旧版本的客户端工具。
pg_dump/pg_restore/pg_upgrade必须使用目标版本目录下的可执行文件。
# 错误!用旧版 pg_dump 导出新库会因版本不符直接失败
# /usr/lib/postgresql/14/bin/pg_dump -d demo > demo.sql
# 正确:使用与服务端一致(或更新)的 pg_dump
/usr/lib/postgresql/18/bin/pg_dump -d demo -Fc -f demo.dump- 不要跨多个主版本"跳级"升级。
pg_upgrade只支持相邻或少数几个版本的直接升级,跨度过大时官方明确要求分步进行。若必须跨 3 个以上主版本,优先选逻辑复制方案。
不推荐:14 ──▶ 18(跨 4 个大版本,风险高、验证成本大)
推荐: 14 ──▶ 16 ──▶ 18(分两步,每步验证)
更优: 14 ──▶ 18 通过逻辑复制(无需停机,可随时回切)- 不要在业务高峰执行升级。即使
--link把停机压到分钟级,升级后首次查询会因统计信息与缓存全冷而变慢,必须留出观察窗口。 - 不要忽略
pg_upgrade的 "check" 步骤。跳过预检直接执行,一旦中途失败,可能同时污染新旧两个数据目录。 - 不要用
latest镜像标签部署生产。官方 Docker 镜像的latest会随新主版本发布而变动,容器重建时可能无声完成主版本升级并导致数据目录不兼容。 - 不要只关注数据库版本而忽略驱动与连接池。升级前需同步确认 JDBC/PG 驱动的版本要求、PgBouncer 对新版本协议的支持情况。
- 不要忘记升级后的统计信息重建。
pg_upgrade在 18 会默认保留规划器统计信息,但跨大版本升级后仍建议主动执行一次ANALYZE。
最佳实践
- 新项目直接采用当前最新稳定大版本(写作时为 18),一次投入换来最长支持期;若是核心金融系统,可选最新稳定版减一。
- 把"最新大版本减一"作为保守团队的默认选择,兼顾能力、生态成熟度与支持期长度。
- 小版本升级按季度例行执行,纳入自动化运维(打补丁 → 重启 → 健康检查),不设人工审批门槛。
- 主版本升级提前 6 个月立项:预留扩展兼容验证、预发演练、业务回归测试与回滚方案设计的时间。
- 优先选择逻辑复制做在线迁移:可做双向同步与灰度切流,回切成本远低于
pg_upgrade。 - 建立版本台账:记录每个实例的版本、EOL 日期、升级负责人与下次复检时间,纳入季度巡检。
- 把 EOL 日期写进监控告警:距离 EOL 少于 365 天时自动告警,而不是靠人记。
- 为升级准备可验证的回滚方案:升级前的物理全备 + WAL 归档是底线,且必须在预发环境完整演练过一次恢复。
- 版本收敛到 1~2 个主版本:多版本混布会显著增加运维、驱动兼容与知识共享成本。
- 升级后做性能基线对比:用
pg_stat_statements抓取升级前后的 Top-N 慢查询,确认没有回归。
下一节
继续学习:第一个 SQL 查询