数据库报错"坏块"别急着删库重来,试试 KingbaseES 的离线修复工具
有回半夜被电话叫醒,客户说业务查询报错,一看日志:数据块损坏。
当时第一反应是找备份恢复。但坏块那张表数据量大,从备份恢复要停业务,客户不同意。后来用 KingbaseES 自带的 sys_walrepairdata 工具,把损坏的块从 WAL 日志里重新拼了回来,业务基本没怎么停。
这工具不算新,但知道的人不多,官方文档叫《KingbaseES 数据离线修复工具使用指南》。今天把它讲明白。
这工具到底是干嘛的
sys_walrepairdata 是 KingbaseES 的 WAL 日志离线修复工具,专门修数据块。
什么场景能用:
- 误删、误更新数据
- 物理备份损坏
- sys checksum 检测到坏块,或者 SQL 执行时报错说检测到坏块、数据部分丢失
注意关键词:离线。修复的时候数据库得关着。
先搞清楚它的限制
| 项目 | 说明 |
|---|---|
| 修复前提 | WAL 日志目录里必须包含坏块对应的日志记录 |
| 数据类型 | 所有数据类型都支持 |
| 语句类型 | 表相关的 DDL 和 DML |
| 跨时间线 | 支持 |
| 修复方式 | 必须离线,数据库关闭状态 |
| 常见失败原因 | wal keep segments 太小,日志被不断删掉,大表的日志不完整 |
最后一行是重点。如果日志被清了,神仙也修不了。所以 wal keep segments 该调大就调大,尤其大表。
参数逐个说
css
-r --backuppath rman 备份目录(可选)
-b --block 要修的块号,-1 表示整表修复;非负整数修指定块,最多同时指定 10 个
-w --walpath WAL 日志目录路径,相对绝对都行
-D --sysdata-datapath 数据目录
-f --relnode 格式 spcid/dbid/relfilenode
-f 这个参数最核心,三个值拼起来定位要修的表:
- spcid:表空间 OID,表空间不存在会报错
- dbid:数据库 OID,路径不存在会报错
- relfilenode:表的数据文件名(不带后缀)
常见表空间 OID 对应关系:
| 表空间名 | OID | 数据目录 |
|---|---|---|
| sys_default | 1663(也可写 0) | base |
| sys_global | 664 | global |
| sysaudit | 1986 | sys_aud |
怎么查 spcid、dbid、relfilenode
知道表名和库名,直接 SQL 查:
sql
-- 查 dbid 和 relfilenode
select oid, datname from sys_database where datname = '你的库名';
-- 查表的 relfilenode
select relfilenode from sys_class where relname = '你的表名';
知道表文件路径的话更好办,从路径里直接能看到对应关系,比如 base/13532/16392 就是 dbid=13532、relfilenode=16392。
实际操作:整表修复
假设表坏了,查出来的参数是 spcid=0、dbid=13532、relfilenode=16392。
第一步,先把数据库关了:
bash
systemctl stop kingbase
第二步,执行修复命令(-b -1 表示整表):
bash
sys_walrepairdata -D /kdb/data -w /kdb/data/sys_wal \
-f 0/13532/16392 -b -1
第三步,启动数据库,查数据:
bash
systemctl start kingbase
sql
select count(*), * from 你的表;
能查出来就说明修好了。
只修指定块号
如果只有个别块坏,可以只修那几块,不用整表:
bash
sys_walrepairdata -D /kdb/data -w /kdb/data/sys_wal \
-f 0/13532/16392 -b 123,456,789
块号从 0 开始算。注意:如果指定的块号超过了文件最大块号,会报"找不到指定块"。
结合 rman 备份修复
如果手头有 rman 备份,还可以用备份文件辅助修复:
bash
sys_walrepairdata -D /kdb/data \
-r /backup/kingbase/20231010-151356F/kb_data \
-b 123,456,789
-r 参数会校验备份目录,检查里面有没有 backup_label 和 sys_control 文件,还要比对备份和当前库的 system_identifier 是否一致,不一致会拒绝。
几个容易忽略的细节
-
relfilenode 对应的数据文件可能不存在。原文件可能被清空或删除了,但只要 WAL 日志完整,照样能恢复出来。所以文件不存在别慌,先确认日志在不在。
-
修复是支持跨时间线的。数据库经历过 PITR 或者切换过时间线,日志里有 history 文件的记录,工具会自己处理。
-
先检查再修。修之前建议先用 sys checksum 或者查询确认坏块范围,心里有数再动手,别一上来就整表修,能修指定块就修指定块,省时间。
-
大表务必确认日志完整性。文档里明确写了,wal keep segments 过小、日志不断被删,对数据量大的表很可能日志不完整,这种修到一半失败是最尴尬的。
写在最后
这个工具救过我一次,也提醒我一件事:WAL 日志这东西,平时看不见摸不着,真到用的时候才后悔没保护好。有条件的话,把 wal keep segments 调大一点,归档也开着,成本不高,但关键时刻是真能救命。
工具是好工具,但最好永远用不上。