pg_dump是PostgreSQL最常用的逻辑备份工具,但在默认情况下它以单进程方式工作,导出和压缩都在一个进程里串行完成。数据库到了几十GB甚至TB级别时,备份窗口可能拖到数小时,业务低峰期根本不够用。实际上,从PostgreSQL 9.3开始,pg_dump就支持了并行导出,再配合合适的压缩算法,备份效率可以成倍提升。本文围绕并行参数、格式选择、压缩策略和恢复配合这几个核心点展开,给出可直接落地的配置方案。

pg_dump并行导出的原理与格式要求
pg_dump的并行能力依赖于-j参数,也就是--jobs。主进程会先序列化数据库的结构和目录信息,然后启动多个worker进程,每个worker负责导出一张或多张表的数据,最后由主进程汇总写入目标文件。需要注意的是,并行导出有一个硬性前提:必须使用directory格式(-Fd)或者自定义格式配合目录输出,plain文本格式(默认的SQL文本)不支持并行。
directory格式会把备份结果写成一个目录,目录里每个表对应一个独立的数据文件(通常是dat文件加压缩),外加一个toc.dat文件记录目录信息。正是因为每张表的数据被拆成了独立文件,多个worker进程才能互不干扰地同时写盘。如果用plain格式,所有SQL都追加写入同一个文件,天然无法并行。下面是一个典型的并行导出命令:
pg_dump -h 127.0.0.1 -p 5432 -U postgres \ -Fd -j 8 -f /data/backup/mydb_dir mydb
关于-j取值的选择,经验值是CPU核心数的一半到两倍之间。因为每个worker既要读数据又要做压缩,CPU往往是瓶颈。如果数据库服务器还有大量在线查询负载,建议从核心数的一半开始试,观察CPU和IO情况再逐步上调。并行度并不是越高越好,worker太多会加剧IO争抢,反而拖慢整体速度。另外要注意,分区表的并行导出在9.3到11版本上有一些限制,PostgreSQL 12之后分区表也能被多个worker并行处理,效果更好。
还有一点容易被忽略:并行导出时需要同步快照(synchronized snapshots),这要求所有worker运行在同一个事务快照下保证数据一致性。PostgreSQL 9.2及以上的服务器默认支持,但如果你用的是热备库(standby),在9.6之前的版本上并行导出会受限,遇到报错可以考虑升级版本或者退回单进程模式。
压缩算法的选择与对比
pg_dump默认使用gzip压缩级别6,速度和压缩率的平衡中规中矩。在并行场景下,压缩算法的选择对总耗时影响很大,因为每个worker都要独立完成压缩工作,压缩速度直接决定了导出速度的上限。
directory格式下可以通过--compress参数指定压缩方法和级别。PostgreSQL 15及之前的版本只支持gzip,写法如--compress=0到--compress=9,其中0表示不压缩。从PostgreSQL 16开始,pg_dump新增了对lz4和zstd的支持,zstd在压缩率和速度上都有明显优势。对比参考:gzip级别6的压缩速度通常在每秒几十MB量级,而zstd默认级别可以达到gzip的3到5倍速度,压缩率还略优;lz4则更快,接近不压缩的写入速度,代价是压缩率较低,适合CPU紧张但磁盘空间充裕的场景。
下面是几种常见的写法:
# gzip级别1,压缩快,适合CPU是瓶颈的场景(PG15及以前) pg_dump -Fd -j 8 --compress=1 -f /backup/mydb_dir mydb # PostgreSQL 16+ 使用zstd,级别3是默认平衡点 pg_dump -Fd -j 8 --compress=zstd:3 -f /backup/mydb_dir mydb # PostgreSQL 16+ 使用lz4,追求极限速度 pg_dump -Fd -j 8 --compress=lz4 -f /backup/mydb_dir mydb # 完全不压缩,交给外部管道或本地磁盘足够大时使用 pg_dump -Fd -j 8 --compress=0 -f /backup/mydb_dir mydb
如果服务器安装的是PostgreSQL 15或更早版本,但又想用zstd,可以通过管道绕一圈:先用pg_dump以directory格式输出到本地不压缩,随后用zstd对目录内文件压缩,或者干脆改成custom格式配合外部压缩工具。不过管道方式会牺牲并行度,更实用的替代方案是先落盘再压缩,或者利用zstd的多线程模式zstd -T8处理备份目录下的各个数据文件,速度同样可观。
备份与恢复的配合优化
备份提速之后,恢复环节往往成为新的瓶颈,尤其是通过pg_restore导入时,建索引和加约束是单线程执行的。想要整体缩短恢复时间,恢复阶段同样要用并行:pg_restore -j N会让数据加载阶段使用多个会话并行执行COPY,索引创建也会尽量并行调度。
# 并行恢复directory格式的备份 pg_restore -h 127.0.0.1 -U postgres \ -d mydb -j 8 /data/backup/mydb_dir # 恢复时关闭压缩校验开销,直接读取 # 如果源是custom格式,同样支持-j参数 pg_restore -Fc -j 8 -d mydb /backup/mydb.dump
恢复前做一些准备能让并行恢复发挥最大效果。首先,目标库可以临时调大maintenance_work_mem,每个并行的索引构建会话都能用到这块内存,索引创建速度明显加快。其次,如果恢复到全新的库,可以把autovacuum临时关闭,并在恢复完成后执行一次ANALYZE更新统计信息,避免恢复过程中的额外开销。另外,恢复目标如果是异地,网络带宽也会成为瓶颈,此时压缩传输比裸传更划算,zstd压缩后的数据量通常只有原始的20%到40%。
日常运维中还有几个实践细节值得注意。第一,监控备份目录的磁盘占用,directory格式下每个worker会各写各的文件,峰值占用可能比单文件备份略高。第二,保留备份元数据,toc.dat一旦损坏整个备份不可用,重要环境建议备份后做一次pg_restore -l验证目录可读。第三,并行度、压缩级别都要结合业务低峰期的IO余量做压测,最好用生产数据的子集演练一遍,记录实际耗时后再定最终的备份脚本参数。一个生产环境中常见的完整脚本示例如下:
#!/bin/bash
BACKUP_DIR=/data/backup/mydb_$(date +%F)
LOG_FILE=/data/backup/mydb_backup.log
pg_dump -h 127.0.0.1 -U postgres \
-Fd -j 8 --compress=zstd:3 \
-f "$BACKUP_DIR" mydb > "$LOG_FILE" 2>&1
# 备份完成后验证目录完整性并保留7天
pg_restore -l "$BACKUP_DIR" > /dev/null 2>&1 \
&& echo "backup ok" >> "$LOG_FILE"
find /data/backup -maxdepth 1 -type d -mtime +7 \
-exec rm -rf {} \;总结一下,pg_dump的并行压缩优化核心在于三点:用directory格式解锁并行能力,用-j参数配合CPU资源选择合理并行度,用zstd或lz4替代默认gzip降低压缩环节的耗时。再配合pg_restore的并行恢复和参数调优,整套备份恢复流程的效率通常能提升数倍,让大数据库的日常备份真正变得可控。
pg_dump并行导出PostgreSQL备份修改时间:2026-09-14 07:07:24