先说结论:迁移项目最坑的环节不是迁数据,是迁之前你根本不知道自己面对的是个什么玩意儿。
这话可能有点糙,但我真是这么觉得的。
我干DBA差不多七八年了,前几年主要做运维,后来公司接信创的单子,我就被拉去做数据迁移。说实话刚做迁移那会儿挺自信的,觉得不就是把数据从A库导到B库么,能有什么难度。直到被一个项目教做人。
头一个让我栽跟头的项目
那个项目是个政务系统,客户那边的老库跑了快十年了,Oracle的。项目经理去现场调研回来,说"表不多,几百张,存储过程有一些,应该不难"。我们就按照他说的估了工期,三个人,一个月,觉得绰绰有余。
结果进场第一天就傻眼了。
我连上库一查,表有两千多张。存储过程四百多个。触发器六百多个。最离谱的是视图——一千多个视图,其中有一大半还是视图套视图,最深的我数过,七层。七层是什么概念呢,就是你要改最底层那个视图,上面六层全得重新检查,不然哪天应用查个数据突然报错,你都不知道是哪一层出的问题。
当时我坐在客户机房里,看着屏幕上的对象列表,脑子里就一个念头:这活儿一个月肯定干不完。
但工期已经跟客户签了。后面的事情可想而知——团队天天加班,改存储过程改到怀疑人生,上线时间硬生生往后拖了一个半月,尾款还被扣了。项目经理在复盘会上问我,为什么前期没把工作量摸清楚。我能说什么呢,我也想摸清楚,但库里几千个对象,你让我一个个去看哪些兼容哪些不兼容?看一个月也看不完啊。
那时候我就意识到一个事儿——迁移项目的风险,百分之八十出在"评估"这一步。不是大家不想评估,是真的没有好办法评估。靠人去看,看不过来;靠经验猜,猜不准。
后来一个同行给我推荐了KDMS。就是KingbaseES配套的那个数据迁移工具,专门干迁移评估和结构转换的活儿。说实话一开始我是半信半疑的,工具能比人看得准?但当时正好又接了个新单子,想着死马当活马医,就试了试。
这一试,后面几个项目我就再没离开过它。
先说它到底是个什么东西
KDMS这东西,你可以理解成一个"迁移体检仪"。你把源库的信息采集上来,它帮你做一次全面扫描,然后出一份报告,告诉你哪些对象能直接迁、哪些要改、改的话大概要花多少时间。
架构上稍微说两句,因为这个跟它好不好用有关系。它分三块:一个是跑在你本地的采集端,一个是跑在云端的评估系统,还有就是人的服务。采集端负责连到你源库上把对象信息扒下来,扒完打包上传到云端,云端那套系统负责做分析,分析完出报告。
我一开始还担心数据安全的问题,毕竟政务和金融的客户对这个特别敏感。后来看了它的采集机制才明白——它采集的不是数据本身,是"元数据"。说人话就是,它只扒表结构定义、存储过程的代码、索引定义这些东西,表里的业务数据一条都不会上传。这个区别很大,表结构说白了不算敏感信息,泄露了也没什么用,所以大部分客户都能接受。
当然也有那种极度敏感的环境,内网完全物理隔离,云端连不上。这种情况他们也支持本地部署的版本,整套评估系统装在你内网里,数据不出网,就是部署麻烦一点。
三种采集方式,对应三种不同的坑
采集端装好之后,我才发现它支持三种采集方式。一开始我只用第一种,后来吃了亏才知道,三种都得用。
第一种,数据库直接采集。 这个最直接,你给它一个源库的账号密码,它自己连上去,把数据字典读一遍,表、视图、存储过程、函数、触发器、索引、约束、序列……所有对象的定义全部拉下来。
Oracle的话,连个普通账号其实就能读大部分数据字典,但保险起见我一般会要一个带SELECT_CATALOG_ROLE的账号。连接配置大概是这样:
数据库类型:Oracle
主机地址:192.168.1.100
端口:1521
服务名:ORCLPDB1
用户名:kdms_collect
密码:**********
采集对象范围:全库 / 指定Schema
点开始之后它就自己跑了,期间你可以看到进度,"正在采集表结构... 312/2047"、"正在采集存储过程..."这种。一个两千多张表的库,大概十几分钟就采完了,比人工一个个查快多了。
第二种,应用采集。 这个是我后来才知道厉害的。数据库采集只能采到库里存在的对象,但你想想,很多系统的SQL根本不是以存储过程的形式存在库里的——是写在应用代码里的,尤其是Java应用,MyBatis的Mapper文件里几百条SQL,或者代码里直接拼字符串。这些SQL你不扫应用代码,根本不知道它们的存在。
应用采集端的工作方式是,把它装到跑应用的那台服务器上,配好你的应用目录,它会去扫描代码文件里的SQL。
应用采集配置
扫描路径:/opt/app/tomcat/webapps/ROOT/WEB-INF/classes
文件类型:.xml .java .properties
SQL识别规则:
- MyBatis <select>/<insert>/<update>/<delete> 标签
- JDBC 字符串拼接
- .sql 脚本文件
我前面说吃过亏——就是有个项目,数据库采集完了兼容度99%,大家都很乐观,结果应用一上线到处报错。为什么?MyBatis里有大量的SQL用了Oracle的ROWNUM,还有一堆用(+)写外连接的,这些东西库里压根没有,数据库采集当然采不到。后来用应用采集一扫,扫出来三千多条内嵌SQL,其中两百多条有兼容性问题。从那以后我定了个规矩:数据库采集和应用采集必须都做,缺一不可。
第三种,历史SQL采集。 这个是抓数据库里历史执行过的SQL。比如Oracle可以从VSQLAREA这些动态性能视图里捞,把数据库最近一段时间实际跑过的SQL语句都捞出来分析。
为什么需要这个?因为有些SQL既不在存储过程里,也不在应用代码里——是运维人员或者报表平台临时手工执行的,或者是BI工具动态生成的。这些SQL平时看不见,但迁移之后如果还得用,就可能出问题。
-- 采集端在Oracle里大概就是捞这类信息
SELECT sql_id, sql_text, executions, last_active_time
FROM v$sqlarea
WHERE last_active_time > SYSDATE - 30
AND parsing_schema_name = 'BUSINESS_USER'
ORDER BY executions DESC;
我一般会让客户先把AWR或者这些SQL视图的保留期调长一点,默认很多系统只留七天,太短了,捞不全。
三种采集方式说起来简单,但这里头其实有个理念上的转变——以前大家理解的"评估对象"就是数据库里那些表啊视图啊,但实际上,一个系统真正依赖的SQL分布在三个地方:库里的、应用里的、还有历史上跑过的。只看其中一个地方,得出的结论一定是片面的。这一点我觉得是KDMS设计上想得比较明白的地方。
采集完之后,好戏才开场
采集包上传到云端之后,就是等评估。评估时间看对象数量,一般几分钟到半小时不等。评估完了,报告会推送到你的账号里,也可以直接在网页上看。
我第一次拿到报告的时候,说实话有点被那个详细程度惊到了。
报告开头是个总览,最显眼的就是几个大数字:对象总数多少,直接兼容多少,需要改造多少,自动转换率多少,预估工作量多少人天。
我给你们看个大概的样子(数字我脱敏处理过,结构是真的):
迁移评估总览
源库类型:Oracle 11g
目标版本:KingbaseES V9
────────────────────────────
对象总数: 3,847
自动兼容: 3,524
需手工改造: 213
可自动转换: 110
────────────────────────────
自动转换率: 97.2%
预估工作量: 18 人天
你们知道我当时什么感觉吗。就像我前面说的那个栽跟头的项目,如果当时有这份报告,我进场第一天就能拿着这张表去找项目经理:你看,3847个对象,213个要手工改,预计18人天,加上联调测试,六周,这才是合理工期。不用瞎猜,不用赌,数字摆在这。
不过这里我要泼一盆冷水,也是我自己踩过的坑——这个预估人天不是绝对准的,它是个参考值。它的计算逻辑大概是根据不兼容对象的数量和复杂度套一个经验系数,但具体到你的项目,还要看干活的人熟不熟悉目标库、业务逻辑有多绕。我后来对比过几个项目,它给出的数字一般偏乐观,实际工期大概是预估的1.2到1.5倍。但即便如此,有个数量级准确的参考,也比拍脑袋强一百倍。
报告细到什么程度呢——逐类拆给你看
总览下面就是分对象类型的详细统计。表、视图、存储过程、函数、触发器、索引、约束、序列……每一类都单独列,兼容多少不兼容多少,不兼容的原因是什么,一条条写清楚。
先说表这一块。表的兼容性问题主要集中在数据类型映射上。比如:
表对象兼容性明细(节选)
────────────────────────────────────
T_ORDER 兼容
T_CUSTOMER 兼容
T_LOG 不兼容 - 字段类型 LONG(建议映射为 TEXT)
T_AMOUNT 需确认 - NUMBER 无精度定义(映射 NUMERIC)
T_BIN_DATA 不兼容 - BFILE 类型(目标库无直接对应)
...
Oracle的NUMBER不写精度的时候,在目标库里映射成NUMERIC,这个大部分情况没问题,但如果你那列存的是整数而且拿来做关联键,建议改成BIGINT或者INTEGER,性能和执行计划都更稳。这种"建议"报告里会标注出来,但最终要不要改还得你自己判断——我觉得这才是对的,工具把问题指出来,决策权留给人,而不是自作主张全给你转了。
还有LONG和LONG RAW这种Oracle的老类型,目标库对应TEXT和BYTEA。BFILE比较麻烦,它本质上是个指向操作系统文件的指针,目标库没有完全对应的东西,这种就得改设计,一般是把文件本身入库成BLOB,或者应用层维护文件路径。报告里会明确告诉你这是"需架构调整"的问题,不是简单改个类型能解决的。
-- KDMS 转换存储过程里干的事,大概长这样
-- LONG 类型的转换示例
-- 原表(Oracle)
CREATE TABLE t_log (
id NUMBER(10),
content LONG
);
-- 转换后
CREATE TABLE t_log (
id INTEGER,
content TEXT
);
然后是视图。视图的问题一般出在语法细节上。比如Oracle特有的外连接(+)写法,还有DUAL表的使用、ROWNUM伪列这些。
-- Oracle 老写法
SELECT e.emp_name, d.dept_name
FROM emp e, dept d
WHERE e.dept_id = d.dept_id(+);
-- 这种 KDMS 的自动转换一般能处理,转成标准的
SELECT e.emp_name, d.dept_name
FROM emp e
LEFT JOIN dept d ON e.dept_id = d.dept_id;
但视图套视图的那种,自动转换就经常出问题。因为转换是单个对象处理的,它能保证这一个视图的语法转对了,但七层嵌套的时候,层层转换累积下来的语义偏差,有时候要到实际跑查询才暴露。我有个项目就是,单个视图检查全是绿的,结果应用一跑,某个深层视图报字段类型不匹配。查了半天才发现,中间有一层做了隐式类型转换,单看没问题,嵌套起来就不对了。所以我的习惯是,视图自动转完之后,那些嵌套超过三层的,全部手工再过一遍。
存储过程是重头戏,也是兼容问题最集中的地方。这个我得多说点。
Oracle的PL/SQL和目标库的过程语言,底子是挺像的,大部分简单逻辑——赋值、IF判断、循环、普通的SELECT INTO——基本能直接转或者自动转。但有几类东西是重灾区:
一个是包(PACKAGE)。Oracle有PACKAGE和PACKAGE BODY的概念,一组相关的过程、函数、变量打包在一起,还有包级别的全局变量。这个东西目标库里没有直接对应的结构,转换的时候一般是拆成一个个独立的存储过程和函数,但包级变量就麻烦了,得用临时表或者会话变量去模拟。如果你的包大量依赖包级变量在过程之间传状态,这种转换基本都得手工介入,自动转换搞不定。
-- Oracle 包的典型结构
CREATE OR REPLACE PACKAGE order_pkg AS
v_batch_no VARCHAR2(20); -- 包级变量
PROCEDURE create_order(p_customer_id NUMBER);
FUNCTION get_batch_no RETURN VARCHAR2;
END order_pkg;
-- 这种结构 KDMS 会标记为"需手工改造"
-- 因为拆包之后 v_batch_no 的跨过程共享语义需要重新实现
第二个是动态SQL。EXECUTE IMMEDIATE和DBMS_SQL这两套。简单的EXECUTE IMMEDIATE 'DELETE FROM t WHERE id=' || v_id这种,自动转换一般没问题。但如果是用DBMS_SQL做的那种很复杂的动态逻辑——动态绑定变量、动态获取列描述、甚至根据查询结果的列数动态处理——这种基本只能手工重写。
第三个是Oracle内置包。DBMS_OUTPUT、DBMS_JOB/DBMS_SCHEDULER、UTL_FILE、UTL_HTTP这些。目标库大部分有对应的替代,但名字和用法不完全一样。比如文件操作,Oracle用UTL_FILE_DIR或者DIRECTORY对象,目标库的方式就不太一样。定时任务也是,DBMS_SCHEDULER的JOB转换过去之后,要在目标库这边重新建调度。
存储过程兼容性问题分布(某项目实际数据)
────────────────────────────────────────
语法直接兼容: 312 个
自动转换成功: 68 个
需手工改造: 47 个
手工改造的47个里面:
PACKAGE相关: 19 个
动态SQL复杂场景: 12 个
Oracle内置包依赖: 9 个
自治事务(PRAGMA): 4 个
其他: 3 个
────────────────────────────────────────
看到没,自动转换能解决大部分,但真正难啃的那47个,才是这个项目工作量的大头。而报告好就好在,它提前告诉你这47个在哪、难在哪,你可以一进场就安排最有经验的人去啃这些硬骨头,剩下的让初级的人处理自动转换的结果就行。资源怎么分配,一目了然。
触发器、函数、索引这些我就不一一细说了。触发器主要是REFERENCING OLD AS ... NEW AS ...这类语法差异,还有语句级和行级触发的细微语义区别。函数的话注意一下确定性(DETERMINISTIC)和管道函数(PIPELINED)的处理。索引大部分都能直接对应,位图索引转的时候要想想——OLTP系统里位图索引用得少,有些转成普通B树索引反而合适,这个要结合实际负载判断,不能机械地"有啥转啥"。
那些报告之外,但报告帮我想到的事
用了KDMS几个项目之后,我发现它最大的价值还不只是那份报告本身。
怎么说呢,它逼着你把"评估"这件事做扎实。以前做项目,评估这一步是很随意的,找个老DBA去现场看两天,回来写个两页纸的评估意见,"整体兼容情况良好,预计工作量XX人天"——就这种,没有任何细节支撑,说穿了就是经验+感觉。
现在有了工具,评估变成了一个有明确输入、明确输出、可复现的过程。你采了哪些库、哪些应用、什么时间采的、评估规则是哪个版本,全部有记录。两个月后真要翻出来对账,报告里写了什么清清楚楚。
而且这个报告拿给客户看,效果特别好。你跟客户说"我觉得这个项目大概要两个月",客户心里是打鼓的,他觉得你在漫天要价。但你把报告打开,指给他看——3847个对象,这是工具扫出来的不是我编的;213个要改,每一个不兼容的原因都列在这;18人天是这么算出来的。客户一看这个,信任度完全不一样。他可能不懂技术,但他看得懂数字,看得懂"每个问题都被列出来了"这件事。
有一次项目中期客户想加范围,要把另一个老系统也并进来。搁以前这事儿就扯皮了,"不就多几张表么"——客户永远觉得加几张表是小事。那次我直接让他给我那个系统的库连接,KDMS现场采集评估,半小时后报告出来:额外1200个对象,其中86个存储过程要手工改,增加12人天。报告往群里一发,客户自己就说"哦那确实得加预算加时间"。你看,工具替我把这个红脸唱了,我都不用开口争。
关于"数据决策"这件事,我再啰嗦两句
这个行业里有个词,叫"经验估算"vs"数据决策",以前我觉得这就是喊口号。现在我算是有点体会了。
经验估算的本质是什么?是拿过去的经验套现在的项目。但问题是,每个系统的历史包袱都不一样,你上个项目四百个存储过程大部分能兼容,不代表这个项目的四百个也能——万一这里头有三十个重度依赖PACKAGE和自治事务的呢?你不知道,你以为你知道。
而工具做的事,是把"这个系统到底长什么样"先原原本本摸清楚,再在这个基础上做判断。它不替你做最终决定,但它保证你做决定的时候,看到的信息是完整的、真实的,而不是项目经理现场看两眼带回来的"表不多"。
当然我也不会把工具神化。前面说了,它的工作量预估偏乐观;复杂的业务逻辑改造,它只能标出"这里有问题",具体怎么改还得靠人;还有一种情况我遇到过,同一个SQL在两个库里语法都能跑、单测都对,但优化器选的执行计划差异巨大,导致上线后性能断崖式下跌——这种"能跑但跑得慢"的问题,静态评估是很难完全发现的,得靠后面的性能测试兜底。
所以我现在的做法是:KDMS评估报告作为整个项目的基线,但不是终点。报告出来后,我会针对那些标记为"需手工改造"的对象逐一人工复核,再补一轮关键SQL的性能验证,最后才定方案。工具负责广度,把所有对象扫一遍,保证不遗漏;人负责深度,把真正复杂的问题啃下来。
再讲个具体的"报告救命"的事儿
前面讲的都是方法论,可能有点虚,说个具体的。
前年做一个医疗相关的系统,HIS,医院那套东西懂的都懂,业务复杂得要命,而且停机窗口特别苛刻——你不能大白天停系统,门诊都挂着号呢。当时院方IT主任信誓旦旦跟我们说,库里东西不多,"我们这系统是当年买的成品,改动很少"。
我们留了个心眼,进场第一件事就是上KDMS采集。结果报告出来,整个项目组倒吸一口凉气:
HIS系统采集结果
────────────────────────
SQL总行数: 98,027 行
表: 5,009 张
存储过程: 105 个
触发器: 191 个
函数: 64 个
物化视图: 2 个
────────────────────────
兼容率: 97.69%
成品系统是真的,但人家这成品规模就有这么大。你要是信了"改动很少"这句话,按一个小项目配资源,进场就是灾难。
不过反过来说,这份报告也给了我们底气——对象虽然多,但兼容率97.69%,真正要手工处理的没多少。后来项目实际做下来,前期评估和改造大概一周就搞定了。院方原来按他们自己的理解,以为至少要折腾一个月,最后听说一周,还专门请我们吃了顿饭。
这就是我说的,报告既能防止你低估风险,也能防止你被规模吓到、或者被客户的错误认知带偏。多还是少,难还是易,不是靠嘴说的,是数据说了算。
一点小经验:评估前的准备工作
最后分享点操作层面的经验吧,新上手的同学可能用得上。
做采集之前,先把这几件事确认了:
第一,源库版本搞清楚。10g、11g、12c还是19c,不同版本的特性差异不小,评估规则是按版本走的,选错了结果会有偏差。
第二,采集账号权限提前申请好。别等到了现场才发现账号没权限读数据字典,客户那边走个审批流程可能就是两三天,干等着。Oracle的话至少保证能访问ALL_OBJECTS、ALL_SOURCE、ALL_TAB_COLUMNS、ALL_INDEXES、ALL_TRIGGERS这些视图。
第三,跟客户确认采集范围。是全库还是只采业务用户?很多库里有大量系统自带的或者其他废弃系统的对象,全采进来报告会掺水,工作量统计也不准。一般我会让客户指定业务Schema,采干净点。
第四,应用采集之前先搞清楚应用部署在哪、有几台服务器。集群部署的应用,代码可能分散在多台机器上,每台都要扫,漏一台就可能漏掉一批SQL。
这些事都不大,但每一件漏了,都可能让评估结果打折扣。工具再好,输入是垃圾,输出也只能是垃圾,这个道理到哪都成立。
行了,上半篇就先聊到这,评估这块的东西我尽量都倒出来了。下半篇我打算讲讲评估之后的事——怎么拿这份报告指导真正的迁移,KFS那套同步和校验的东西怎么配合着用,还有割接那天晚上到底是怎么过来的。
这大概就是我理解的,一个数据迁移工具正确的使用姿势。