PostgreSQL教程FG107-PG数据恢复实战教程
本文档详细介绍PostgreSQL数据库数据恢复的各种方法和技巧,包括逻辑恢复、物理恢复、时间点恢复等操作,风哥教程参考PostgreSQL官方文档Backup and Restore内容,适合DBA在生产环境中实施数据恢复操作。
Part01-基础概念与理论知识
1.1 PostgreSQL数据恢复概念
PostgreSQL数据恢复是指将数据库从备份状态恢复到正常可用状态的过程。根据备份类型和恢复目标的不同,恢复方式也有所区别。逻辑恢复使用pg_restore或psql工具恢复SQL脚本或归档文件,物理恢复使用pg_basebackup备份文件恢复整个数据库实例。更多视频教程www.fgedu.net.cn
- 支持多种恢复方式:逻辑恢复、物理恢复、时间点恢复
- 支持选择性恢复:恢复指定表、Schema或数据库
- 支持时间点恢复:恢复到任意时间点
- 恢复过程需要谨慎操作,避免数据丢失
- 恢复前必须验证备份文件的完整性
- 建议在测试环境先验证恢复流程
1.2 PostgreSQL恢复类型分类
# 1. 逻辑恢复
# – 使用pg_restore恢复pg_dump备份
# – 使用psql恢复SQL文本备份
# – 支持选择性恢复
# – 恢复速度较慢
# 2. 物理恢复
# – 使用pg_basebackup备份文件恢复
# – 恢复整个数据目录
# – 恢复速度快
# – 需要停机操作
# 3. 时间点恢复(PITR)
# – 基于物理备份+WAL归档
# – 恢复到指定时间点
# – 恢复到指定事务ID
# – 恢复到命名恢复点
# 4. 备库切换恢复
# – 主库故障时切换到备库
# – 最小化业务中断
# – 需要预先搭建备库
# 恢复方式对比
| 恢复方式 | 恢复粒度 | 恢复速度 | 停机时间 | 适用场景 |
|———|———|———|———|———|
| 逻辑恢复 | 表/库 | 慢 | 短 | 误删表/数据 |
| 物理恢复 | 整库 | 快 | 长 | 数据文件损坏 |
| PITR | 整库 | 中 | 长 | 时间点恢复 |
| 备库切换 | 整库 | 快 | 极短 | 主库故障 |
1.3 PostgreSQL恢复工具介绍
PostgreSQL恢复工具:
- pg_restore:恢复pg_dump生成的自定义格式备份
- psql:恢复SQL文本格式的备份
- pg_basebackup:创建物理备份(用于恢复)
- pg_rewind:同步主备库数据目录
- recovery.conf:PostgreSQL 12之前的恢复配置文件
- postgresql.auto.conf:PostgreSQL 12+的恢复配置
Part02-生产环境规划与建议
2.1 PostgreSQL恢复策略规划
# 1. 恢复时间目标(RTO)
# – 核心业务:RTO < 1小时
# - 重要业务:RTO < 4小时
# - 一般业务:RTO < 24小时
# 2. 恢复点目标(RPO)
# - 核心业务:RPO = 0(实时复制)
# - 重要业务:RPO < 1小时
# - 一般业务:RPO < 24小时
# 3. 恢复策略选择
# 表级误删:逻辑恢复
# 数据文件损坏:物理恢复
# 时间点恢复:PITR
# 主库故障:备库切换
# 4. 恢复流程规划
# 步骤1:确认故障类型
# 步骤2:选择恢复策略
# 步骤3:准备恢复环境
# 步骤4:执行恢复操作
# 步骤5:验证恢复结果
# 步骤6:恢复业务服务
# 5. 恢复演练计划
# 每月:表级恢复演练
# 每季:PITR恢复演练
# 每年:灾难恢复演练
2.2 PostgreSQL恢复场景分析
PostgreSQL恢复场景分析:
- 误删表:使用pg_restore恢复指定表
- 误删数据:恢复到删除前的时间点
- 数据文件损坏:物理恢复或备库切换
- 系统崩溃:物理恢复
- 存储故障:从异地备份恢复
- 人为破坏:时间点恢复
2.3 PostgreSQL恢复测试规划
# 1. 测试环境
# – 独立的测试服务器
# – 与生产环境配置一致
# – 定期更新测试数据
# 2. 测试内容
# – 逻辑备份恢复测试
# – 物理备份恢复测试
# – PITR恢复测试
# – 备库切换测试
# 3. 测试频率
# – 每周:验证备份文件完整性
# – 每月:表级恢复测试
# – 每季:完整恢复测试
# – 每年:灾难恢复演练
# 4. 测试记录
# – 记录测试时间
# – 记录恢复时间
# – 记录遇到的问题
# – 记录改进措施
# 5. 测试报告
# – 恢复成功率
# – 恢复时间统计
# – 问题分析和改进建议
Part03-生产环境项目实施方案
3.1 PostgreSQL逻辑恢复实战
3.1.1 恢复SQL文本备份
# 1. 查看备份文件
$ ls -lh /postgresql/backup/daily/fgedudb_20260407.sql
-rw-r–r– 1 pgsql fgedudb 512M Apr 7 02:00 /postgresql/backup/daily/fgedudb_20260407.sql
# 2. 创建目标数据库
$ createdb -h fgedu.localhost -p 5432 -U fgedu fgedudb_restore
# 3. 执行恢复
$ psql -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -f /postgresql/backup/daily/fgedudb_20260407.sql
# 执行过程输出
SET
SET
SET
CREATE SCHEMA
CREATE TABLE
ALTER TABLE
CREATE INDEX
…
# 4. 恢复压缩的备份
$ gunzip -c /postgresql/backup/daily/fgedudb_20260407.sql.gz | psql -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore
# 5. 恢复整个实例
$ psql -h fgedu.localhost -p 5432 -U fgedu -f /postgresql/backup/daily/all_databases_20260407.sql
# 执行过程输出
CREATE ROLE
ALTER ROLE
CREATE DATABASE
\connect fgedudb
SET
CREATE TABLE
…
# 6. 验证恢复结果
$ psql -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -c “SELECT count(*) FROM fgedu_orders;”
count
——-
500000
(1 row)
$ psql -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -c “\dt fgedu.*”
List of relations
Schema | Name | Type | Owner
——–+—————–+——-+——-
fgedu | fgedu_orders | table | fgedu
fgedu | fgedu_customers | table | fgedu
fgedu | fgedu_products | table | fgedu
(3 rows)
3.1.2 使用pg_restore恢复
# 1. 查看备份内容
$ pg_restore -l /postgresql/backup/daily/fgedudb_20260407.dump | head -50
;
; Archive created at 2026-04-07 02:00:00
; dbname: fgedudb
; TOC Entries: 256
;
3264; 1262 16384 DATABASE – fgedudb fgedu
3; 2615 16385 SCHEMA – fgedu fgedu
…
# 2. 创建目标数据库
$ createdb -h fgedu.localhost -p 5432 -U fgedu fgedudb_restore
# 3. 恢复整个数据库
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore /postgresql/backup/daily/fgedudb_20260407.dump
# 执行过程输出(无输出表示成功)
# 4. 并行恢复
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -j 4 /postgresql/backup/daily/fgedudb_20260407.dump
# 5. 只恢复结构
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore –schema-only /postgresql/backup/daily/fgedudb_20260407.dump
# 6. 只恢复数据
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore –data-only /postgresql/backup/daily/fgedudb_20260407.dump
# 7. 恢复指定表
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -t fgedu_orders /postgresql/backup/daily/fgedudb_20260407.dump
# 8. 使用过滤列表恢复
$ pg_restore -l /postgresql/backup/daily/fgedudb_20260407.dump > /tmp/toc.list
# 编辑toc.list,取消注释要恢复的对象
$ vi /tmp/toc.list
# 使用过滤列表恢复
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -L /tmp/toc.list /postgresql/backup/daily/fgedudb_20260407.dump
# 9. 恢复目录格式备份
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -j 4 /postgresql/backup/daily/fgedudb_20260407_dir
# 10. 验证恢复结果
$ psql -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_restore -c “SELECT count(*) FROM fgedu_orders;”
count
——-
500000
(1 row)
3.2 PostgreSQL物理恢复实战
3.2.1 恢复基础备份
# 1. 停止数据库服务
$ pg_ctl -D /postgresql/fgdata stop
waiting for server to shut down…. done
server stopped
# 2. 备份当前数据目录(如果需要)
$ mv /postgresql/fgdata /postgresql/fgdata.bak
# 3. 恢复基础备份(plain格式)
$ cp -r /postgresql/backup/base/20260407 /postgresql/fgdata
$ chown -R pgsql:fgedudb /postgresql/fgdata
$ chmod 700 /postgresql/fgdata
# 4. 恢复基础备份(tar格式)
$ mkdir -p /postgresql/fgdata
$ tar -xzf /postgresql/backup/base/base.tar.gz -C /postgresql/fgdata
$ tar -xzf /postgresql/backup/base/pg_wal.tar.gz -C /postgresql/fgdata/pg_wal
$ chown -R pgsql:fgedudb /postgresql/fgdata
$ chmod 700 /postgresql/fgdata
# 5. 恢复表空间
$ mkdir -p /postgresql/tbs_data
$ tar -xzf /postgresql/backup/base/fgedutbs_data.tar.gz -C /postgresql/tbs_data
$ chown -R pgsql:fgedudb /postgresql/tbs_data
# 6. 验证恢复的文件
$ ls -la /postgresql/fgdata/
total 128
drwx—— 20 pgsql fgedudb 4096 Apr 7 02:00 .
drwxr-xr-x 3 pgsql fgedudb 4096 Apr 7 02:00 ..
-rw——- 1 pgsql fgedudb 3 Apr 7 02:00 PG_VERSION
drwx—— 5 pgsql fgedudb 4096 Apr 7 02:00 base
drwx—— 2 pgsql fgedudb 4096 Apr 7 02:00 global
…
# 7. 启动数据库
$ pg_ctl -D /postgresql/fgdata start
waiting for server to start…. done
server started
# 8. 验证数据库状态
$ psql -U fgedu -d fgedudb -c “SELECT version();”
version
—————————————————————————————————————–
PostgreSQL 18.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 9.3.1 20200408, 64-bit
(1 row)
3.3 PostgreSQL时间点恢复实战
3.3.1 恢复到指定时间点
# 1. 确定恢复目标时间
# 假设误操作发生在 2026-04-07 10:30:00
# 2. 准备恢复环境
$ pg_ctl -D /postgresql/fgdata stop
$ mv /postgresql/fgdata /postgresql/fgdata.bak
$ cp -r /postgresql/backup/base/20260407 /postgresql/fgdata
$ chown -R pgsql:fgedudb /postgresql/fgdata
$ chmod 700 /postgresql/fgdata
# 3. 配置恢复参数
$ vi /postgresql/fgdata/postgresql.auto.conf
# 添加以下内容
restore_command = ‘cp /postgresql/archive/%f %p’
recovery_target_time = ‘2026-04-07 10:30:00’
recovery_target_action = ‘promote’
# 4. 创建恢复信号文件
$ touch /postgresql/fgdata/recovery.signal
# 5. 启动恢复
$ pg_ctl -D /postgresql/fgdata start
waiting for server to start…. done
server started
# 6. 监控恢复日志
$ tail -f /postgresql/fgdata/log/postgresql-*.log
2026-04-07 10:00:00.123 CST [12345] LOG: starting archive recovery
2026-04-07 10:00:00.456 CST [12345] LOG: restored log file “000000010000000000000001” from archive
2026-04-07 10:00:01.789 CST [12345] LOG: redo starts at 0/2000028
2026-04-07 10:00:02.012 CST [12345] LOG: consistent recovery state reached at 0/3000000
…
2026-04-07 10:05:00.345 CST [12345] LOG: recovery stopping before commit of transaction 12345, time 2026-04-07 10:30:00
2026-04-07 10:05:01.678 CST [12345] LOG: redo done at 0/65000000
2026-04-07 10:05:02.901 CST [12345] LOG: selected new timeline ID: 2
2026-04-07 10:05:03.234 CST [12345] LOG: archive recovery complete
2026-04-07 10:05:04.567 CST [12345] LOG: database system is ready to accept connections
# 7. 验证恢复结果
$ psql -U fgedu -d fgedudb -c “SELECT count(*) FROM fgedu_orders;”
count
——-
450000
(1 row)
# 8. 检查是否已提升为主库
$ psql -U fgedu -d fgedudb -c “SELECT pg_is_in_recovery();”
pg_is_in_recovery
——————-
f
(1 row)
3.3.2 恢复到指定事务ID
# 1. 查找事务ID
$ pg_waldump /postgresql/archive/000000010000000000000065 | grep -i “delete”
rmgr: Heap len (rec/tot): 59/ 331, tx: 12345, lsn: 0/65000128, prev 0/64000128, desc: DELETE off 1, flags 0x00 KEYS_UPDATED , blkref #0: rel 1663/16384/12345 blk 0
# 2. 配置恢复参数
$ vi /postgresql/fgdata/postgresql.auto.conf
restore_command = ‘cp /postgresql/archive/%f %p’
recovery_target_xid = ‘12345’
recovery_target_inclusive = false
recovery_target_action = ‘promote’
# 3. 创建恢复信号文件
$ touch /postgresql/fgdata/recovery.signal
# 4. 启动恢复
$ pg_ctl -D /postgresql/fgdata start
# 5. 恢复到命名恢复点
# 先创建恢复点
$ psql -U fgedu -d fgedudb -c “SELECT pg_create_restore_point(‘before_migration’);”
pg_create_restore_point
————————-
0/70000128
(1 row)
# 配置恢复到命名恢复点
$ vi /postgresql/fgdata/postgresql.auto.conf
restore_command = ‘cp /postgresql/archive/%f %p’
recovery_target_name = ‘before_migration’
recovery_target_action = ‘promote’
# 6. 恢复到最早一致点
$ vi /postgresql/fgdata/postgresql.auto.conf
restore_command = ‘cp /postgresql/archive/%f %p’
recovery_target = ‘immediate’
recovery_target_action = ‘pause’
Part04-生产案例与实战讲解
4.1 PostgreSQL表级恢复案例
# 场景:误删fgedu_orders表
# 1. 确认表已被删除
$ psql -U fgedu -d fgedudb -c “\dt fgedu_orders”
Did not find any relation named “fgedu_orders”.
# 2. 查找最近的备份
$ ls -lt /postgresql/backup/daily/ | head -5
total 0
drwx—— 2 pgsql fgedudb 48 Apr 7 02:00 20260407
drwx—— 2 pgsql fgedudb 48 Apr 6 02:00 20260406
drwx—— 2 pgsql fgedudb 48 Apr 5 02:00 20260405
# 3. 创建临时恢复数据库
$ createdb -h fgedu.localhost -p 5432 -U fgedu fgedudb_temp
# 4. 恢复备份到临时数据库
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_temp -t fgedu_orders /postgresql/backup/daily/20260407/fgedudb_full.dump
# 5. 验证恢复的表
$ psql -U fgedu -d fgedudb_temp -c “SELECT count(*) FROM fgedu_orders;”
count
——-
500000
(1 row)
# 6. 导出表数据
$ pg_dump -h fgedu.localhost -p 5432 -U fgedu -d fgedudb_temp -t fgedu_orders -F c -f /tmp/fgedu_orders.dump
# 7. 恢复到原数据库
$ pg_restore -h fgedu.localhost -p 5432 -U fgedu -d fgedudb /tmp/fgedu_orders.dump
# 8. 验证恢复结果
$ psql -U fgedu -d fgedudb -c “SELECT count(*) FROM fgedu_orders;”
count
——-
500000
(1 row)
# 9. 清理临时数据库
$ dropdb -h fgedu.localhost -p 5432 -U fgedu fgedudb_temp
4.2 PostgreSQL误操作恢复案例
# 场景:误执行了DELETE操作,删除了重要数据
# 1. 确认误操作时间
$ psql -U fgedu -d fgedudb -c “SELECT now();”
now
——————————-
2026-04-07 10:35:00.123456+08
(1 row)
# 假设误操作发生在 10:30:00
# 2. 检查当前数据量
$ psql -U fgedu -d fgedudb -c “SELECT count(*) FROM fgedu_orders WHERE status = ‘pending’;”
count
——-
100
(1 row)
# 正常应该是 10000 条
# 3. 准备恢复环境(在另一台服务器)
$ pg_ctl -D /postgresql/fgdata stop
$ cp -r /postgresql/backup/base/20260407 /postgresql/fgdata_recovery
$ chown -R pgsql:fgedudb /postgresql/fgdata_recovery
$ chmod 700 /postgresql/fgdata_recovery
# 4. 配置时间点恢复
$ vi /postgresql/fgdata_recovery/postgresql.auto.conf
restore_command = ‘cp /postgresql/archive/%f %p’
recovery_target_time = ‘2026-04-07 10:29:00’
recovery_target_action = ‘promote’
# 5. 创建恢复信号
$ touch /postgresql/fgdata_recovery/recovery.signal
# 6. 启动恢复
$ pg_ctl -D /postgresql/fgdata_recovery -l /postgresql/logs/recovery.log start
# 7. 等待恢复完成
$ grep “database system is ready” /postgresql/logs/recovery.log
2026-04-07 10:40:00.567 CST [12345] LOG: database system is ready to accept connections
# 8. 验证恢复的数据
$ psql -h fgedu.localhost -p 5433 -U fgedu -d fgedudb -c “SELECT count(*) FROM fgedu_orders WHERE status = ‘pending’;”
count
——-
10000
(1 row)
# 9. 导出需要恢复的数据
$ psql -h fgedu.localhost -p 5433 -U fgedu -d fgedudb -c “\COPY (SELECT * FROM fgedu_orders WHERE status = ‘pending’) TO ‘/tmp/pending_orders.csv’ WITH CSV HEADER”
# 10. 导入到原数据库
$ psql -U fgedu -d fgedudb -c “\COPY fgedu_orders FROM ‘/tmp/pending_orders.csv’ WITH CSV HEADER”
# 11. 验证最终结果
$ psql -U fgedu -d fgedudb -c “SELECT count(*) FROM fgedu_orders WHERE status = ‘pending’;”
count
——-
10000
(1 row)
# 12. 清理恢复环境
$ pg_ctl -D /postgresql/fgdata_recovery stop
$ rm -rf /postgresql/fgdata_recovery
4.3 PostgreSQL灾难恢复案例
# disaster_recovery.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: http://www.fgedu.net.cn
# PostgreSQL灾难恢复脚本
PGHOME=/postgresql/fgapp
PGDATA=/postgresql/fgdata
BACKUP_DIR=/postgresql/backup/base
ARCHIVE_DIR=/postgresql/archive
LOG_FILE=/postgresql/scripts/logs/disaster_recovery.log
log_message() {
echo “$(date ‘+%Y-%m-%d %H:%M:%S’) – $1” >> $LOG_FILE
}
# 检查备份文件
check_backup() {
log_message “检查备份文件…”
if [ ! -d “$BACKUP_DIR” ]; then
log_message “ERROR: 备份目录不存在”
return 1
fi
local latest_backup=$(ls -d $BACKUP_DIR/20* | tail -1)
if [ -z “$latest_backup” ]; then
log_message “ERROR: 没有找到备份文件”
return 1
fi
log_message “找到最新备份: $latest_backup”
}
# 检查WAL归档
check_archive() {
log_message “检查WAL归档…”
if [ ! -d “$ARCHIVE_DIR” ]; then
log_message “WARNING: WAL归档目录不存在”
return 0
fi
local archive_count=$(ls $ARCHIVE_DIR | wc -l)
log_message “WAL归档文件数量: $archive_count”
}
# 执行恢复
do_recovery() {
local target_time=$1
local latest_backup=$(ls -d $BACKUP_DIR/20* | tail -1)
log_message “开始恢复…”
# 停止数据库
$PGHOME/bin/pg_ctl -D $PGDATA stop -m immediate 2>/dev/null
# 备份当前数据目录
if [ -d “$PGDATA” ]; then
mv $PGDATA ${PGDATA}.corrupt.$(date +%Y%m%d%H%M%S)
fi
# 恢复基础备份
cp -r $latest_backup $PGDATA
chown -R pgsql:fgedudb $PGDATA
chmod 700 $PGDATA
# 配置恢复参数
cat > $PGDATA/postgresql.auto.conf << EOF
restore_command = 'cp $ARCHIVE_DIR/%f %p'
recovery_target_time = '$target_time'
recovery_target_action = 'promote'
EOF
# 创建恢复信号
touch $PGDATA/recovery.signal
# 启动数据库
$PGHOME/bin/pg_ctl -D $PGDATA -l $LOG_FILE start
log_message "恢复启动完成,请检查日志确认恢复状态"
}
# 主函数
main() {
local target_time=$1
if [ -z "$target_time" ]; then
echo "Usage: $0
echo “Example: $0 ‘2026-04-07 10:30:00′”
exit 1
fi
log_message “==========================================”
log_message “开始灾难恢复”
log_message “目标时间: $target_time”
log_message “==========================================”
check_backup && check_archive && do_recovery $target_time
log_message “==========================================”
log_message “灾难恢复脚本执行完成”
log_message “==========================================”
}
main “$@”
Part05-风哥经验总结与分享
5.1 PostgreSQL恢复最佳实践
PostgreSQL恢复最佳实践:
- 备份验证:定期验证备份文件的完整性
- 恢复演练:定期进行恢复演练
- 文档记录:记录详细的恢复流程
- 测试环境:在测试环境验证恢复流程
- 时间预估:预估恢复时间,制定RTO目标
- 监控告警:监控恢复过程,及时发现问题
5.2 PostgreSQL恢复脚本库
/postgresql/scripts/recovery/
├── logical_restore.sh # 逻辑恢复脚本
├── physical_restore.sh # 物理恢复脚本
├── pitr_restore.sh # 时间点恢复脚本
├── table_restore.sh # 表级恢复脚本
├── disaster_recovery.sh # 灾难恢复脚本
└── conf/
└── recovery.conf # 恢复配置
5.3 PostgreSQL恢复检查清单
# 恢复前检查
– [ ] 确认故障类型和范围
– [ ] 确认备份文件可用
– [ ] 确认WAL归档可用
– [ ] 确认目标恢复时间点
– [ ] 确认磁盘空间充足
# 恢复中监控
– [ ] 监控恢复进度
– [ ] 监控系统资源
– [ ] 记录恢复日志
– [ ] 准备回滚方案
# 恢复后验证
– [ ] 验证数据完整性
– [ ] 验证数据一致性
– [ ] 验证应用连接
– [ ] 验证业务功能
# 恢复后处理
– [ ] 更新监控配置
– [ ] 更新备份策略
– [ ] 编写恢复报告
– [ ] 总结经验教训
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
