PostgreSQL 运维
PostgreSQL 运维的核心不是“数据库能启动”,而是做到四件事:
- 故障能够及时发现。
- 性能问题能够快速定位。
- 数据能够按目标时间恢复。
- 配置、升级和维护操作可以回滚。
对于你的 PostgreSQL 18 + TimescaleDB 股票数据环境,还要额外关注数据新鲜度、Hypertable 分块和后台策略任务。
| 领域 | 核心目标 | 主要对象 |
|---|---|---|
| 可用性 | 数据库持续提供服务 | 进程、端口、连接 |
| 性能 | SQL 延迟稳定 | 慢 SQL、锁、I/O、内存 |
| 容量 | 防止磁盘耗尽 | 数据、索引、WAL、日志 |
| 数据维护 | 控制膨胀、保持统计准确 | VACUUM、ANALYZE |
| 高可用 | 主库故障后可切换 | 流复制、复制延迟 |
| 数据保护 | 可恢复到指定时间 | 备份、WAL、PITR |
| 安全 | 限制访问和高危权限 | 角色、SSL、pg_hba.conf |
| 变更管理 | 升级和配置变更可控 | 配置、扩展、版本 |
建议建立三层检查:
- 操作系统层:CPU、内存、磁盘、I/O、网络、OOM。
- PostgreSQL 层:连接、锁、事务、WAL、Vacuum、复制。
- 业务层:股票数据日期、数量、重复数据、任务状态。
pg_isready \
-h 127.0.0.1 \
-p 5432 \
-d ashare \
-t 3
pg_isready 只能证明服务器有响应,最好再执行真实 SQL:
psql \
-h 127.0.0.1 \
-U monitor_user \
-d ashare \
-Atqc "SELECT 1"
SELECT
now() AS checked_at,
current_setting('server_version') AS server_version,
pg_postmaster_start_time() AS started_at,
now() - pg_postmaster_start_time() AS uptime,
pg_is_in_recovery() AS is_standby;
其中:
is_standby = false:通常是主库。is_standby = true:数据库处于恢复或备库状态。
WITH conn AS (
SELECT
count(*) AS total,
count(*) FILTER (WHERE state = 'active') AS active,
count(*) FILTER (WHERE state = 'idle') AS idle,
count(*) FILTER (
WHERE state LIKE 'idle in transaction%'
) AS idle_in_transaction
FROM pg_stat_activity
WHERE backend_type = 'client backend'
),
cfg AS (
SELECT current_setting('max_connections')::integer AS max_connections
)
SELECT
conn.*,
cfg.max_connections,
round(100.0 * conn.total / cfg.max_connections, 2) AS usage_pct
FROM conn
CROSS JOIN cfg;
初始告警线可以设置为:
| 指标 | 参考告警值 |
|---|---|
| 连接使用率 | 70% 警告,85% 严重 |
idle in transaction |
超过 1 分钟 |
| 普通 API SQL | 超过 30 秒 |
| 锁等待 | 超过 10~30 秒 |
这些只是起始值,应根据实际基线和 SLA 调整。
不要一遇到连接不足就提高 max_connections。大量连接会增加进程、内存和调度开销,应该先检查:
- 应用是否泄漏连接。
- SQLAlchemy 连接池是否合理。
- 是否有大量空闲连接。
- 是否需要 PgBouncer。
- API、ETL、管理任务是否使用独立账号和连接池。
建议应用设置明确的 application_name,这样能在 pg_stat_activity 中快速定位 FastAPI、行情采集和后台任务。
SELECT
pid,
datname,
usename,
application_name,
client_addr,
state,
wait_event_type,
wait_event,
clock_timestamp() - query_start AS query_duration,
clock_timestamp() - xact_start AS transaction_duration,
left(query, 300) AS query
FROM pg_stat_activity
WHERE state = 'active'
AND pid <> pg_backend_pid()
AND query_start < clock_timestamp() - interval '30 seconds'
ORDER BY query_start;
state='active' 不代表 SQL 一直在使用 CPU。如果同时存在 wait_event,可能正在等待:
Lock:等待表锁、行锁。IO:等待磁盘。Client:等待客户端发送或接收数据。LWLock:等待 PostgreSQL 内部共享结构。IPC:等待其他后台进程。
PostgreSQL 18 可通过 pg_stat_activity、pg_stat_io、pg_stat_wal、pg_stat_checkpointer 等视图观察运行状态。PostgreSQL 18 统计监控文档
SELECT
pid,
datname,
usename,
application_name,
client_addr,
state,
clock_timestamp() - xact_start AS transaction_age,
clock_timestamp() - state_change AS idle_age,
left(query, 300) AS last_query
FROM pg_stat_activity
WHERE state LIKE 'idle in transaction%'
ORDER BY xact_start;
空闲事务危害很大:
- 长时间保留旧版本数据。
- 阻碍 VACUUM 清理。
- 导致表和索引膨胀。
- 长时间持有锁。
- 可能拖慢备库清理。
可以针对 API 用户设置:
ALTER ROLE ashare_api IN DATABASE ashare
SET idle_in_transaction_session_timeout = '60s';
ALTER ROLE ashare_api IN DATABASE ashare
SET statement_timeout = '30s';
ALTER ROLE ashare_api IN DATABASE ashare
SET lock_timeout = '5s';
ETL 任务不应直接复用 API 的短超时配置,应使用独立角色和更合适的超时。
SELECT
blocked.pid AS blocked_pid,
blocked.usename AS blocked_user,
blocked.application_name AS blocked_app,
clock_timestamp() - blocked.query_start AS blocked_duration,
left(blocked.query, 200) AS blocked_query,
blocker.pid AS blocker_pid,
blocker.usename AS blocker_user,
blocker.application_name AS blocker_app,
clock_timestamp() - blocker.xact_start AS blocker_xact_duration,
left(blocker.query, 200) AS blocker_query
FROM pg_stat_activity AS blocked
JOIN LATERAL unnest(pg_blocking_pids(blocked.pid))
AS p(blocker_pid) ON true
JOIN pg_stat_activity AS blocker
ON blocker.pid = p.blocker_pid
ORDER BY blocked.query_start;
优先取消当前 SQL:
SELECT pg_cancel_backend(12345);
如果连接本身必须断开:
SELECT pg_terminate_backend(12345);
处理顺序应当是:
- 确认阻塞者身份和业务。
- 判断事务能否安全回滚。
- 优先通知应用主动提交或回滚。
- 使用
pg_cancel_backend()。 - 最后才使用
pg_terminate_backend()。
不要自动终止所有阻塞者,因为阻塞者可能正在执行关键资金、订单或批量导入事务。锁信息主要来自 pg_locks,但官方也建议结合 pg_stat_activity 和 pg_blocking_pids() 分析。锁监控文档
你的配置已经包含 TimescaleDB,因此要保留原值:
shared_preload_libraries = 'timescaledb,pg_stat_statements'
compute_query_id = on
pg_stat_statements.track = top
track_io_timing = on
track_wal_io_timing = on
修改 shared_preload_libraries 后需要重启 PostgreSQL。
在业务数据库中安装扩展:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
查看累计资源消耗最大的 SQL:
SELECT
queryid,
calls,
round(total_exec_time::numeric, 2) AS total_ms,
round(mean_exec_time::numeric, 2) AS mean_ms,
round(max_exec_time::numeric, 2) AS max_ms,
rows,
shared_blks_read,
shared_blks_hit,
temp_blks_written,
wal_bytes,
left(query, 300) AS query
FROM pg_stat_statements
WHERE dbid = (
SELECT oid
FROM pg_database
WHERE datname = current_database()
)
ORDER BY total_exec_time DESC
LIMIT 20;
分析重点:
total_exec_time:累计占用最多的 SQL。mean_exec_time:单次平均最慢。calls:高频小 SQL。temp_blks_written:排序或哈希发生磁盘溢出。shared_blks_read:读取压力。wal_bytes:写入产生的 WAL 数量。
pg_stat_statements 需要通过 shared_preload_libraries 加载,并依赖查询标识符。pg_stat_statements 文档
logging_collector = on
log_min_duration_statement = '500ms'
log_lock_waits = on
deadlock_timeout = '1s'
log_temp_files = '64MB'
log_autovacuum_min_duration = '1s'
log_line_prefix = '%m [%p] %q%u@%d/%a '
不建议在生产库长期设置:
log_statement = 'all'
它可能:
- 产生海量日志。
- 记录密码、手机号、策略参数等敏感值。
- 增加磁盘和 I/O 压力。
log_min_duration_statement 会记录超过指定耗时的完整 SQL,是定位慢查询的基础手段。PostgreSQL 日志配置
SELECT
datname,
pg_size_pretty(pg_database_size(datname)) AS database_size
FROM pg_database
WHERE datallowconn
ORDER BY pg_database_size(datname) DESC;
SELECT
schemaname,
relname,
pg_size_pretty(pg_relation_size(relid)) AS table_size,
pg_size_pretty(pg_indexes_size(relid)) AS index_size,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 20;
这只能看到当前大小。要判断增长速度,必须定期采集并保存历史数据,例如每天记录:
- 数据库总大小。
- 最大表大小。
- WAL 产生量。
- 临时文件量。
- 每日新增行情行数。
SQL 大小函数看不到文件系统剩余空间,还必须在操作系统层监控:
- 数据目录所在磁盘。
pg_wal所在磁盘。- 表空间磁盘。
- 日志磁盘。
- 备份目录。
- inode 数量。
处理顺序:
- 确认是数据、WAL、日志、临时文件还是备份增长。
- 检查 WAL 归档是否失败。
- 检查复制槽是否长期不活跃。
- 检查日志轮转。
- 扩容或安全转移非数据库文件。
- 确认空间充足后处理根因。
绝对不要手工删除:
PGDATA/base
PGDATA/global
PGDATA/pg_xact
PGDATA/pg_wal
尤其不能通过删除 pg_wal 来解决磁盘告警,这可能直接让实例无法恢复。
PostgreSQL 的 UPDATE 和 DELETE 不会立即物理删除旧行,而是产生死元组,依靠 VACUUM 回收空间。
SELECT
schemaname,
relname,
n_live_tup,
n_dead_tup,
round(
100.0 * n_dead_tup /
greatest(n_live_tup + n_dead_tup, 1),
2
) AS dead_pct,
last_autovacuum,
last_autoanalyze,
autovacuum_count,
autoanalyze_count
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC
LIMIT 30;
注意:n_live_tup 和 n_dead_tup 是估算值,不能仅凭某个百分比判定表膨胀。
大批量导入、更新或删除后,可以在低负载时间执行:
VACUUM (ANALYZE, VERBOSE) market.daily_quote;
只更新统计信息:
ANALYZE market.daily_quote;
普通 VACUUM:
- 清理死元组。
- 将空间标记为可重复使用。
- 通常不会把空间归还操作系统。
- 一般不阻塞正常增删改查。
VACUUM FULL:
- 重写整张表。
- 需要额外临时磁盘空间。
- 获取
ACCESS EXCLUSIVE锁。 - 会阻塞表的所有正常访问。
所以生产运维应优先调好 autovacuum,尽量避免依赖 VACUUM FULL。PostgreSQL 日常 Vacuum 文档
SELECT
datname,
age(datfrozenxid) AS xid_age,
current_setting('autovacuum_freeze_max_age')::bigint
AS autovacuum_trigger_age,
round(
100.0 * age(datfrozenxid) /
current_setting('autovacuum_freeze_max_age')::numeric,
2
) AS trigger_usage_pct
FROM pg_database
WHERE datallowconn
ORDER BY xid_age DESC;
这个百分比表示接近“强制防回卷 autovacuum”的程度,并不是直接表示距离 20 亿事务回卷还有多少。
如果持续接近阈值,应检查:
- autovacuum 是否被长事务阻挡。
- 是否有大量写入。
- 表是否过大。
- autovacuum worker 是否不足。
- 是否存在
idle in transaction。 - 磁盘 I/O 是否已经饱和。
不要随意取消名称带有:
(to prevent wraparound)
的 autovacuum 任务。
索引确实膨胀或损坏时,生产库优先考虑:
REINDEX INDEX CONCURRENTLY market.idx_daily_quote_code_date;
并发重建允许正常读写,但耗时更长、资源开销更大。普通 REINDEX 会阻塞写入。REINDEX 官方说明
不能仅因为 idx_scan = 0 就删除索引,因为统计可能刚刚重置,也可能该索引只用于月末或故障查询。
SELECT
backend_type,
object,
context,
reads,
pg_size_pretty(read_bytes::bigint) AS read_size,
round(read_time::numeric, 2) AS read_ms,
writes,
pg_size_pretty(write_bytes::bigint) AS write_size,
round(write_time::numeric, 2) AS write_ms,
fsyncs,
round(fsync_time::numeric, 2) AS fsync_ms
FROM pg_stat_io
ORDER BY coalesce(read_bytes, 0) + coalesce(write_bytes, 0) DESC;
PostgreSQL 18 的 pg_stat_io 可以区分:
- 普通 relation I/O。
- 临时 relation I/O。
- WAL I/O。
bulkread、bulkwrite、vacuum等场景。
其中耗时列只有启用 track_io_timing 或 track_wal_io_timing 后才有意义。
SELECT
wal_records,
wal_fpi,
pg_size_pretty(wal_bytes::bigint) AS generated_wal,
wal_buffers_full,
stats_reset
FROM pg_stat_wal;
需要观察“单位时间增量”,不能只看累计值。
WAL 突然增长通常与以下操作有关:
- 大批量
INSERT、UPDATE、DELETE。 - 创建或重建索引。
- 大量全页写。
- VACUUM FULL。
- 批量回填历史行情。
- 逻辑复制。
SELECT
num_timed,
num_requested,
num_done,
write_time,
sync_time,
buffers_written,
stats_reset
FROM pg_stat_checkpointer;
如果单位时间内 num_requested 远高于 num_timed,可能意味着:
max_wal_size太小。- 写入突增。
- 有程序频繁执行
CHECKPOINT。 - 备份或其他操作触发检查点。
也要结合磁盘延迟和 WAL 速率判断,不能只凭累计计数修改参数。
SELECT
archived_count,
failed_count,
last_archived_wal,
last_archived_time,
last_failed_wal,
last_failed_time,
stats_reset
FROM pg_stat_archiver;
重点不是 failed_count 是否为零,而是它是否继续增长,以及最新 WAL 是否持续成功归档。
需要告警:
failed_count增加。- 长时间没有成功归档,但数据库持续产生 WAL。
pg_wal目录快速增长。- 备份超出预期完成时间。
每次备份至少记录:
- 开始时间、结束时间。
- PostgreSQL 和 TimescaleDB 版本。
- 数据库或实例名称。
- 备份类型。
- 文件大小。
- 命令退出码。
- 校验结果。
- 备份存储位置。
- 保留期限。
物理备份可以执行:
pg_verifybackup /srv/pgbackup/base/2026-09-14
但只有成功完成独立恢复、业务查询和 PITR 演练,才能真正证明备份可用。
流复制备库不是备份:生产库误删数据后,误操作同样会复制到备库。
SELECT
application_name,
client_addr,
state,
sync_state,
write_lag,
flush_lag,
replay_lag,
CASE
WHEN replay_lsn IS NULL THEN NULL
ELSE pg_size_pretty(
pg_wal_lsn_diff(
pg_current_wal_lsn(),
replay_lsn
)::bigint
)
END AS replay_lag_bytes
FROM pg_stat_replication
ORDER BY application_name;
需要同时观察:
state是否为streaming。- 字节延迟。
- 时间延迟。
- 备库能否实际查询。
- 备库磁盘是否充足。
主库空闲时,pg_last_xact_replay_timestamp() 计算出的时间差可能看起来很大,因此时间延迟不能单独作为判断标准。
SELECT
slot_name,
slot_type,
active,
active_pid,
wal_status,
restart_lsn,
confirmed_flush_lsn,
CASE
WHEN restart_lsn IS NULL THEN NULL
ELSE pg_size_pretty(
pg_wal_lsn_diff(
pg_current_wal_lsn(),
restart_lsn
)::bigint
)
END AS retained_wal
FROM pg_replication_slots
ORDER BY slot_name;
长期不活跃的复制槽可能让主库无限保留 WAL,最终填满磁盘。可通过 max_slot_wal_keep_size 限制风险,但不要看到槽不活跃就直接删除,应先确认对应备库或订阅是否已经废弃。PostgreSQL 流复制说明
SELECT
extname,
extversion
FROM pg_extension
WHERE extname = 'timescaledb';
SELECT
name,
default_version,
installed_version
FROM pg_available_extensions
WHERE name = 'timescaledb';
SHOW shared_preload_libraries;
SELECT
hypertable_schema,
hypertable_name,
num_dimensions,
num_chunks,
compression_enabled
FROM timescaledb_information.hypertables
ORDER BY hypertable_schema, hypertable_name;
SELECT
hypertable_schema,
hypertable_name,
pg_size_pretty(bytes) AS total_size
FROM (
SELECT
hypertable_schema,
hypertable_name,
hypertable_size(
format(
'%I.%I',
hypertable_schema,
hypertable_name
)::regclass
) AS bytes
FROM timescaledb_information.hypertables
) AS s
ORDER BY bytes DESC;
SELECT
hypertable_schema,
hypertable_name,
count(*) AS chunk_count,
count(*) FILTER (WHERE is_compressed) AS compressed_chunks,
count(*) FILTER (WHERE NOT is_compressed) AS uncompressed_chunks
FROM timescaledb_information.chunks
GROUP BY hypertable_schema, hypertable_name
ORDER BY chunk_count DESC;
需要警惕:
- Chunk 数量异常增长。
- Chunk 太小,导致规划和元数据开销变大。
- Chunk 太大,导致压缩、Vacuum 和索引维护耗时过长。
- 压缩策略应执行但大量历史 Chunk 没有压缩。
SELECT
j.job_id,
j.proc_name,
j.hypertable_schema,
j.hypertable_name,
j.scheduled,
j.schedule_interval,
s.job_status,
s.last_run_status,
s.last_run_duration,
s.last_successful_finish,
s.next_start,
s.total_runs,
s.total_successes,
s.total_failures
FROM timescaledb_information.jobs AS j
LEFT JOIN timescaledb_information.job_stats AS s
USING (job_id)
ORDER BY
s.total_failures DESC NULLS LAST,
j.job_id;
查看错误详情:
SELECT *
FROM timescaledb_information.job_errors
ORDER BY finish_time DESC
LIMIT 20;
重点检查:
scheduled = false:任务是否被人为暂停。last_run_status = 'Failed'。total_failures是否持续增加。last_run_duration是否已经接近或超过调度间隔。- 连续聚合、压缩、保留策略是否按预期运行。
相关字段可参考 TimescaleDB job_stats。
数据库正常不代表业务数据正常。行情库还需要业务级检查。
SELECT
trade_date,
count(*) AS row_count,
count(DISTINCT code) AS stock_count
FROM market.daily_quote
WHERE trade_date >= current_date - 10
GROUP BY trade_date
ORDER BY trade_date DESC;
应该和交易日历比较,不能简单要求每天都有数据,因为周末和节假日不开市。
SELECT
code,
trade_date,
count(*) AS duplicate_count
FROM market.daily_quote
GROUP BY code, trade_date
HAVING count(*) > 1
ORDER BY duplicate_count DESC
LIMIT 100;
建议存在唯一约束:
UNIQUE (code, trade_date)
例如:
batch_id
data_source
trade_date
started_at
finished_at
expected_rows
actual_rows
success_rows
failed_rows
status
error_message
checksum
这样可以区分:
- 数据源没有数据。
- 爬虫失败。
- 数据下载成功但入库失败。
- 入库成功但数量不完整。
- 重复执行导致数据覆盖。
大规模历史行情回填完成后,应执行:
ANALYZE market.daily_quote;
SELECT
name,
setting,
unit,
context,
source,
sourcefile,
sourceline,
pending_restart
FROM pg_settings
WHERE pending_restart
ORDER BY name;
SELECT
sourcefile,
sourceline,
name,
setting,
applied,
error
FROM pg_file_settings
WHERE error IS NOT NULL
OR NOT applied
ORDER BY sourcefile, sourceline;
检查 HBA:
SELECT *
FROM pg_hba_file_rules
WHERE error IS NOT NULL;
确认无误后重载:
SELECT pg_reload_conf();
部分参数只能重启生效,pending_restart=true 可以帮助识别。postgresql.auto.conf 中的 ALTER SYSTEM 配置会覆盖 postgresql.conf,排查配置“不生效”时必须一起检查。PostgreSQL 参数管理
pg_ctl status -D /path/to/data
pg_ctl stop \
-D /path/to/data \
-m fast
pg_ctl restart \
-D /path/to/data \
-m fast
生产环境通常由 systemd、容器编排或对应安装工具管理服务,避免同时使用多个服务管理方式。
关闭模式:
| 模式 | 行为 |
|---|---|
smart |
等待所有客户端主动断开 |
fast |
断开客户端并回滚事务,推荐日常使用 |
immediate |
立即停止,下次启动进行崩溃恢复 |
除紧急情况外不要使用 immediate,更不要直接 kill -9 PostgreSQL 主进程。pg_ctl 官方文档
CREATE ROLE monitor_user LOGIN;
GRANT pg_monitor TO monitor_user;
维护角色可以按需授予:
GRANT pg_maintain TO maintenance_user;
pg_monitor 用于读取监控视图,pg_maintain 可执行 VACUUM、ANALYZE、REINDEX 等维护操作。它们比直接授予超级用户更安全。PostgreSQL 预定义角色
SELECT
rolname,
rolsuper,
rolcreaterole,
rolcreatedb,
rolreplication,
rolbypassrls,
rolcanlogin,
rolvaliduntil
FROM pg_roles
ORDER BY
rolsuper DESC,
rolcreaterole DESC,
rolname;
基本原则:
- 应用程序不能使用超级用户。
- 对象所有者最好使用
NOLOGIN角色。 - API、行情采集、只读分析、备份、监控使用不同角色。
- 限制
CONNECT、SchemaUSAGE和表权限。 - 定期检查长期不使用的登录角色。
- 远程连接优先使用
hostssl。 - 避免
trust和宽泛的0.0.0.0/0。 - 使用 SCRAM-SHA-256。
PostgreSQL 18 已将 MD5 密码支持标记为弃用;pg_hba.conf 按从上到下寻找第一条匹配规则,不会在认证失败后继续匹配下一条。pg_hba.conf 文档
依次检查:
pg_isready。- PostgreSQL 服务状态。
- 数据库日志。
- 磁盘和 inode。
- 是否发生 OOM。
max_connections是否耗尽。- 端口和
listen_addresses。 pg_hba.conf。- TLS 证书是否过期。
- 数据目录权限。
依次检查:
- 活跃会话和长 SQL。
- 锁阻塞。
- 长事务和空闲事务。
pg_stat_statements。- 临时文件增长。
pg_stat_io。- CPU、内存和磁盘延迟。
- autovacuum 是否被阻塞。
- WAL、检查点和归档。
- TimescaleDB 后台任务。
- 最近是否发布代码或修改执行计划相关配置。
重点检查:
- 归档失败造成
pg_wal累积。 - 不活跃复制槽保留 WAL。
- 日志没有轮转。
- 大事务产生大量临时文件。
- 批量更新造成表、索引膨胀。
- 备份存放在数据盘且未清理。
- TimescaleDB Chunk 或连续聚合快速增长。
- 立即停止相关写入任务。
- 记录误操作时间、时区、SQL 和相关用户。
- 保留当前 WAL。
- 在隔离实例执行 PITR。
- 验证恢复点。
- 导出误删对象。
- 审核后导回生产库。
不要直接在生产数据目录上反复尝试恢复。
| 周期 | 检查内容 |
|---|---|
| 每分钟 | 可连接性、磁盘、连接率、复制状态 |
| 每 5 分钟 | 长 SQL、锁等待、WAL 归档、复制槽 |
| 每小时 | WAL 增量、检查点、临时文件、Timescale 任务 |
| 每日 | 备份结果、死元组、XID 年龄、数据新鲜度 |
| 每周 | 慢 SQL、容量增长、索引情况、角色变更 |
| 每月 | 完整恢复、PITR 演练、补丁评估 |
| 每季度 | 故障切换演练、权限审计、容量规划 |
真正的告警应该基于“单位时间变化”,例如:
- 最近 5 分钟增加了多少 WAL。
- 最近 1 小时发生多少归档失败。
- 最近 24 小时数据库增长多少。
- TimescaleDB 任务连续失败多少次。
只看累计总数容易误判。
如果当前仍是 PostgreSQL 18.3,截至 2026 年 9 月,官方当前维护版本已经是 PostgreSQL 18.6。18.6 修复了 28 个安全漏洞和 110 多个错误,因此建议尽快在恢复副本上验证 TimescaleDB、扩展和业务 SQL,然后安排小版本更新。PostgreSQL 18.6 发布说明
小版本升级通常:
- 不需要
pg_upgrade。 - 不需要
pg_dump/pg_restore。 - 需要停止服务、更新二进制并重新启动。
- 仍然必须提前完成备份和恢复验证。
- 必须阅读被跳过版本的发布说明和特殊处理步骤。
- 必须确认 TimescaleDB 及其他扩展包兼容。
升级前先记录:
SELECT version();
SELECT
extname,
extversion
FROM pg_extension
ORDER BY extname;
一套成熟的 PostgreSQL 运维,最终应形成闭环:
监控发现 → SQL 定位 → 控制影响 → 修复根因
→ 验证数据 → 记录复盘 → 更新告警和操作手册
如果有需要,可以设置“每周 PostgreSQL 运维巡检”,用于定期检查备份、膨胀、慢 SQL 和版本补丁。