备份完不算完,先还原到临时库验一遍

备份脚本挂了定时,监控面板天天绿着,备份目录里每天躺一个新文件,看着挺让人安心。可真要用它的那天------误删了一张表、或者机器坏了得换一台恢复------不少人才头一次发现:这备份还原不回来。文件是空的、少了几个对象、版本对不上,各种情况都有。

备份「跑成功了」和备份「真能用」,中间隔着一次几乎没人主动做的事:把它还原出来看看。这篇就干这一件事,把一个 custom 备份还原到临时库,再一项一项验过去------数据对不对、对象全不全、约束还在不在、业务查询跑不跑得通。第 1 篇讲过的 sys_dump、sys_restore 参数这里不重复,重点是一套验证的思路。

照例说一句账号:这篇要建库、删库,是 DBA 的活,所以用 system 连。日常开发查查改改,普通用户就够,别一上来就抱着管理员账号。演示库叫 backup_src_db,三张表的结构是商品、客户、订单那一套,带主键、外键、唯一约束、check、索引和一个视图,数据里也有中文。

先给源库留一组基线

备份之前,先在源库查一组数据记下来。注意不是查「表在不在」,而是查几个业务上能说明问题的值:

scss 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d backup_src_db -c "
select
  count(*) as order_count,
  sum(total_amount) as amount_sum,
  max(created_at) as last_created_at
from t_bak_order;"
​
ksql -h 127.0.0.1 -p 54321 -U system -d backup_src_db -c "
select * from v_bak_customer_amount order by customer_id;"

订单表 5 行、金额合计 1235.10、最后一单是 2026-06-30 09:50:00;视图按客户汇总,张三 2 单 288.50、李四 2 单 880.00、王五 1 单 66.60。

为什么不直接 select count(*) 完事?因为行数对得上,不代表数据没错位。少灌了一行金额、某个字段乱了序,单看行数发现不了。金额合计、最后一条时间这种指标,掺进了具体的值,恢复后拿来对账才靠得住。这组数就是后面验证的「标准答案」。

备份,然后先别急着还原

备份成 custom 格式,文件放进一个带日期的目录:

bash 复制代码
BACKUP_DIR=/acowbo/kingbase/backups/verify_20260630
mkdir -p "$BACKUP_DIR"
​
sys_dump -h 127.0.0.1 -p 54321 -U system -d backup_src_db -F c -f "$BACKUP_DIR/backup_src_db.dump"
ls -lh "$BACKUP_DIR/backup_src_db.dump"
​
sys_restore -l "$BACKUP_DIR/backup_src_db.dump" | sed -n '1,80p'

文件 6.7K,躺在那儿了。但文件存在只是第一层------里面装的东西齐不齐,得用 sys_restore -l 看一眼归档目录再说。

输出头部写着这份归档的身份:dbname: backup_src_db、TOC Entries: 20、Format: CUSTOM、从 12.1 的库导出。下面 Selected TOC Entries 一条条列着里面有什么:wmsys 这个 KES 自带的 schema、两张表 t_bak_customer 和 t_bak_order、序列、视图 v_bak_customer_amount、表数据、各种约束、那个 idx_bak_order_customer_created 索引、还有外键 t_bak_order_customer_id_fkey。该有的对象都在清单里。

这一步的意义在于,还没动手恢复,就能先确认备份不是个空壳------20 个 TOC 条目、表数据和约束都列着,至少归档本身是完整的。custom 格式能这么列目录,纯文本备份就得自己 grep 了。

还原到临时库,别碰源库

关键一点:还原到一个新建的临时库,不要往源库上还原。临时库名字起得显眼点,一看就知道是干嘛的:

perl 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d app_db -c "drop database if exists backup_verify_db;"
ksql -h 127.0.0.1 -p 54321 -U system -d app_db -c "create database backup_verify_db;"
​
sys_restore -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -v "$BACKUP_DIR/backup_src_db.dump"

-v 让 sys_restore 把每一步都打出来:连接、建 wmsys schema、建两张表、建序列、建视图、灌数据------这里能看到 finish restoring contents of table "public.t_bak_customer" 3 rows、t_bak_order 5 rows,行数和源库对得上;再往下建主键、唯一约束、索引,最后建外键 t_bak_order_customer_id_fkey。整个恢复过程一步不落地走完了。

不过 -v 跑完没报错,只能说「还原命令成功了」,不等于「数据和源库一致」。命令成功是必要条件,不是充分条件,下面还得自己查。

数据对不对,两边拉出来比

源库和临时库各跑一遍同样的汇总,把库名也查出来,并排放着看:

scss 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d backup_src_db -c "
select 'backup_src_db' as db_name,
  count(*) as order_count, sum(total_amount) as amount_sum, max(created_at) as last_created_at
from t_bak_order;"
​
ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "
select 'backup_verify_db' as db_name,
  count(*) as order_count, sum(total_amount) as amount_sum, max(created_at) as last_created_at
from t_bak_order;"

两边都是 5 / 1235.10 / 2026-06-30 09:50:00,跟备份前那组基线一字不差。到这儿,数据这一关算过了------不是因为命令没报错,是因为这几个业务指标真对上了。

对象、约束、索引,一个都不能少

数据对上了,还得看结构。备份恢复从来不只是几行数据的事,约束、索引、视图都是恢复结果的一部分。先看表和视图:

perl 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "\dt"
ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "\dv"

\dt 两张表 t_bak_customer、t_bak_order 都在。\dv 列出来三个视图,别被多出来的两个吓到------sys_stat_statements 和 sys_stat_statements_all 是 KES 自带的统计视图,跟这个库的备份没关系,你要找的是 v_bak_customer_amount,它在。

再把订单表的约束和索引拉出来看定义:

ini 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "
select c.conname, c.contype, _get_constraintdef(c.oid) as constraint_def
from _constraint c
where c.conrelid = 'public.t_bak_order'::regclass
order by c.conname;"

ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "
select indexname, indexdef from _indexes
where schemaname = 'public' and tablename = 't_bak_order'
order by indexname;"

订单表上五个约束全回来了:外键 customer_id 指向客户表、order_no 的唯一约束、order_status 限定 paid/pending/refund 的 check、total_amount > 0 的 check、还有主键。索引也在,包括那个 (customer_id, created_at desc) 的联合索引。

这一步要是省了,很容易掉坑:假如恢复只回来了数据、没回来约束,库当时看着一切正常,等后面业务往里写脏数据,外键和 check 不拦了,问题就埋下了。所以约束在不在,得专门确认,不能默认它跟着数据一起回来了。

跑业务查询,再故意撞一次约束

光「能查」还不够,得让数据真正参与一次业务逻辑。先跑视图:

css 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "
select * from v_bak_customer_amount order by customer_id;"

视图算出来张三 288.50、李四 880.00、王五 66.60,和源库基线完全一致------说明视图定义、底层的 join 和聚合都正常工作。

然后故意撞一下约束,插一条客户根本不存在的订单:

less 复制代码
ksql -h 127.0.0.1 -p 54321 -U system -d backup_verify_db -c "
insert into t_bak_order(order_no, customer_id, total_amount, order_status, created_at)
values ('BKO-BAD-001', 999, 10.00, 'paid', timestamp '2026-06-30 10:00:00');"

外键直接把它顶回来了:

sql 复制代码
ERROR:  insert or update on table "t_bak_order" violates foreign key constraint "t_bak_order_customer_id_fkey"
DETAIL:  Key (customer_id)=(999) is not present in table "t_bak_customer".

这一下才算把约束验透。前面 constraint 里查到约束定义存在,那只是「定义在」;这里真插一条非法数据被拦下来,证明的是约束「在干活」。两者不是一回事------定义还在、但因为某种原因没生效的情况,是真会发生的。

备份文件本身也得能追溯

最后补一组文件层面的信息,记下来:

bash 复制代码
ls -lh "$BACKUP_DIR/backup_src_db.dump"
sha256sum "$BACKUP_DIR/backup_src_db.dump"

文件大小能一眼看出异常------突然冒出来一个 0 字节或者小得离谱的备份,多半是哪步出错了。sha256 这串哈希的用处要说准确:它能在备份传到异地、归档一段时间之后,核对文件有没有被改动或损坏。但它只管「文件这串字节还是不是原来那串」,证明不了「这个库能恢复」------能不能恢复,是前面还原到临时库、把数据和对象逐项验过来确认的。哈希和恢复验证是两件事,别拿哈希对得上当作备份可用。

这套流程到底验出了什么

回头看一遍:备份前留了基线,备份后先用 sys_restore -l 确认归档不是空壳,还原到临时库、不碰源库,数据按业务指标对账,表/视图/约束/索引逐项查过,又拿一条非法写入确认约束真在拦,最后给文件留了大小和哈希。一个备份能走完这一套,才敢说它「能用」,而不只是「跑成功了」。

也得把话说清楚:这验的是「备份文件可用性」,不是一次生产恢复。真到线上恢复,还要考虑停机窗口、连接和权限切换、应用怎么切过去、要恢复到哪个时间点------那是另一篇的事。但反过来说,连还原到临时库这关都没过的备份,上面那些就更无从谈起。备份这东西,定时跑起来只是开了个头,定期捞出来验一遍,它才真正成了你的后路。

相关推荐
金銀銅鐵几秒前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路33 分钟前
go-grpc设计思想
开发语言·后端·golang
system_error_x1 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn3 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈3 小时前
AI 读你的提示词,其实很没耐心
后端
用户8356290780514 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我123454 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒4 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记4 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk598784 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端