金仓数据库逻辑备份实战:从全库导出到 Schema 替换的完整闭环

发布时间:2026/6/28 6:36:15
金仓数据库逻辑备份实战:从全库导出到 Schema 替换的完整闭环 做运维这些年,我越来越相信一句话:备份不是为了平时好看,而是为了出事那一刻能救命。逻辑备份这东西,看着简单,真到了要恢复的时候,各种坑就一个接一个冒出来了。表名大小写、schema 不一致、owner 没跟着换,哪一个处理不好,恢复出来的库都不是你想要的那个样子。这篇文章我想把金仓数据库(KingbaseES)逻辑层面的备份与恢复彻底讲透,从最基础的全库导出,一直聊到恢复时怎么把旧 schema 干净地换成新的。内容都是平时踩过坑、验证过的东西,希望能让你少走点弯路。一、逻辑备份的三种导出格式金仓的逻辑备份核心工具是sys_dump,它支持三种导出格式,分别对应不同的场景。我习惯先把这三种格式的区别讲清楚,因为后面恢复用什么命令,完全取决于你导出时选了哪种。第一种是纯文本格式,参数是-Fp,导出的就是一个普通的.sql文件,里面全是可读的 SQL 语句。这种格式最大的好处是透明,你可以直接打开看,甚至能用文本编辑器改。# su - kingbase$mkdir-p/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)$ sys_dump-h127.0.0.1-p54321-Usystem-ddbtest-f/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)/dbtest.sql第二种是自定义二进制格式,参数-Fc,导出的是一个.dmp文件。这种格式压缩过,体积小,而且恢复时灵活度高,可以选择性地只恢复某些对象。# su - kingbase$mkdir-p/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)$ sys_dump-h127.0.0.1-p54321-Usystem-ddbtest-Fc-f/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)/dbtest.dmp第三种是目录格式,参数-Fd,它会把备份内容拆成一个目录里的多个文件。这是唯一支持并行备份的格式,通过-j参数指定并行度,大库备份能快不少。# su - kingbase$ sys_dump-h127.0.0.1-p54321-Usystem-ddbtest-Fd-j4-f/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)要注意目录格式有个小细节:如果目标目录已经存在,得先删掉再备份,不然会出问题。二、不只是全库,还能精细到 Schema 和单表实际工作里,很多时候我们并不需要整库备份,可能只想保住某个 schema 或者某张关键表。sys_dump用-n指定 schema,用-t指定表。只备份某个 schema:$ sys_dump-h127.0.0.1-p54321-Usystem-ddbtest-npublic-f/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)/public.sql只备份某张表:$ sys_dump-h127.0.0.1-p54321-Usystem-ddbtest-ttest-f/home/kingbase/backup/sys_dump_$(date%Y%m%d%H)/test.sql这里有几个我反复提醒新人的点:加-a参数表示只备份数据不要结构,加-s参数则相反,只要结构不要数据。还有一个容易被忽略但很关键的特性:sys_dump只转储备份开始那一刻的快照,也就是说备份过程中发生的数据变更不会被包含进去。这个机制保证了备份的一致性,但你心里得清楚这条边界在哪。三、那个最容易让人栽跟头的坑:表名大小写说到-t指定表名,我必须单独拎出来讲一个坑,因为它实在太典型了。当你的表名是大小写混合的时候,sys_dump经常会报no matching tables were found,明明表就在那儿,它就是找不到。问题的根子不在数据库,而在 Linux 的 shell 语法。我们先理解一下金仓里表名是怎么存的。在大小写不敏感的环境下(enable_ci为on),你建表时不加双引号,表名会被统一转成小写存进数据字典。TEST# create table dD (id int );CREATETABLETEST# select relname from pg_class where relnamedd;relname---------dd(1row)但如果你建表时给表名加了双引号,它就会原样保留大小写混合的形态:createtablegD(idint);TEST# select relname from pg_class where relnamegD;relname---------gD(1row)这时候问题就来了。你在sys_dump命令里写-t hGF,本意是想保留大小写,但双引号在 shell 里会被先一步解析掉,传给sys_dump的其实只剩下hGF,而数据字典里存的是带引号语义的标识符,两边对不上,自然就报错。[kingbase2localhost V8]$ sys_dump-Usystem-dtest-p2920-FC-thGF-f/opt/Kingbase/ES/V8/dd1.dmp sys_dump: error: no matching tables were found正确的写法有两种,核心都是让双引号能真正传到sys_dump那一层。第一种用转义符:sys_dump-Usystem-dtest-p2920-FC-t\hGF\-f/opt/Kingbase/ES/V8/db1.dmp第二种用单引号把双引号包起来,因为 shell 里单引号内的内容是纯字符串,不做任何解析:sys_dump-Usystem-dtest-p2920-FC-thGF-f/opt/Kingbase/ES/V8/db2.dmp记住这个区别:shell 里单引号是字面字符串,双引号有特殊含义会触发变量解析,所以涉及大小写混合表名时,要么转义要么用单引号包裹。顺带提一句大小写敏感和不敏感环境的差异。敏感环境(enable_ci为off)下,小写表、大写表、混合表可以同时存在,互不冲突。而不敏感环境下,无论你写ag、Ag还是AG,系统只认其中一种,后面再想建另一种形态的同名表,就会直接报relation already exists。这个特性在迁移和恢复时尤其要留心。四、恢复:导出格式决定了你用什么命令讲完备份,接下来是恢复。这里有个铁律:用什么命令恢复,取决于你当初是什么格式导出的。纯文本的.sql文件只能用ksql恢复,这是没有商量余地的。恢复前记得先把数据库建出来。# su - kingbase$ createdb-h127.0.0.1-p54321-Usystem dbtest $ ksql-h127.0.0.1-p54321-Usystem-ddbtest-f/home/kingbase/backup/sys_dump_2023060615/dbtest.sql自定义格式和目录格式则用sys_restore:# 自定义格式$ sys_restore-h127.0.0.1-p54321-Usystem-ddbtest /home/kingbase/backup/sys_dump_2023060615/dbtest.dmp# 目录格式,同样支持并行$ sys_restore-h127.0.0.1-p54321-Usystem-ddbtest-Fd-j4/home/kingbase/backup/sys_dump_2023060615用sys_restore时有个参数细节得提醒:-d和-f不能一起用,你只要用-d指定目标库就行,不需要再用-f单独去指文件位置。这一点我见过不少人搞混。恢复 schema 或单表的逻辑类似,如果当初导的是.sql,那就还是ksql配-f:$ ksql-h127.0.0.1-p54321-Usystem-ddbtest-f/home/kingbase/backup/sys_dump_2023060615/public.sql五、进阶玩法:恢复时把旧 Schema 换成新的最后聊一个稍微高级、但实战中很实用的需求:恢复的时候,我不想用原来的 schema,想换成一个新的。比如源库里数据都在abc这个 schema 下,我希望导进目标库时落到u2下面。sys_restore提供了-g和-G参数来做这件事。但这里有个非常容易被忽略的陷阱:光加-g -G,表确实会落到新 schema,可是表的 owner 还是老的!如果你连 owner 也想一起换掉,必须再加一个-O参数。我用一个完整的测试来说明。先准备环境,建一个abc用户、abc库、abcschema,里面放张t1表,owner 和 schema 都是abc。再建一个超级用户u2和对应的u2schema。导出abc库:sys_dump-Uabc-Fc-fabc.dmp abc-p2920加上-O、-g、-G三个参数恢复,目标 schema 指定为u2:sys_restore-Uu2-dabc-Fc-p2920-gabc-Gu2-Oabc.dmp恢复完查一下,t1表的 schema 和 owner 都变成u2了,这正是我们想要的:abc-# \c abc u2abc-# \dListofrelationsSchema|Name|Type|Owner--------------------------------------------public|sys_stat_statements|view|system u2|t1|table|u2(2rows)作为对比,如果不加-O,你会看到 schema 虽然换成了u2,但 owner 倔强地还是abc:sys_restore-Uu2-dabc-Fc-p2920-gabc-Gu2 abc.dmp-- 结果里 t1 的 Owner 仍然是 abc除了用参数,还有一条更朴素的路子:导出成.sql文本,然后直接用sed命令把里面的 schema 名字全替换掉。sys_dump-Usystem-Fp-fabc.sql abc-p2920sed-is/abc/u2/gabc.sqlsed-is/public/u2/gabc.sql ksql abc-Usystem-fabc.sql这种方式直观好懂,但有个明显短板:面对大数据量的库,文本替换会很慢,而且全局替换容易误伤(比如表名里恰好也含abc字样)。所以小库可以这么玩,大库我还是建议老老实实用sys_restore的参数。写在最后逻辑备份这套东西,真正的难点从来不是命令本身,而是那些藏在细节里的边界条件:三种格式各自的恢复方式、大小写混合表名在 shell 里的转义、sys_restore的参数互斥、还有 owner 跟 schema 替换不同步的问题。把这些坑一个个填平,你的备份恢复流程才算真正可靠。我的建议始终如一:生产环境一定要定期做恢复演练。备份文件躺在硬盘上不叫备份,能在需要的时候完整、正确地恢复出来,那才叫真正的容灾能力。