KingbaseES“零改造“核心技术揭秘从MySQL迁移的隐形战场到平滑过渡指南前阵子做了个KingbaseES迁移项目客户系统跑在MySQL上十几年业务模块上百个存储过程、定时任务、报表查询全都有。领导给的要求就一句应用代码尽量不改上线窗口只有周末两天。这就是所谓“零改造”的真实处境——不是真的一行代码不动而是要把改动量压缩到业务方感知不到的程度。做国产数据库迁移的人都知道真正的战场从来不在数据导入导出而在兼容性细节你以为换个驱动就能跑结果第一个SQL就报语法错误你觉得数据迁过去就行结果一条SQL的查询结果对不上。这篇文章我把从MySQL迁到KingbaseES过程中真正决定成败的那些细节完整梳理一遍包括兼容模式怎么搭、驱动怎么配、SQL和函数有哪些坑、存储过程怎么处理、迁移之后怎么验证。内容全部来自实际项目适合正在做国产化数据库选型或已经拿到迁移任务的DBA、后端开发、架构师参考。1. “零改造”的底层逻辑兼容模式到底兼容了什么1.1 兼容模式不是模拟器语法解析层与执行层的边界很多人的第一反应是KingbaseES既然是国产数据库那它应该“长得像”MySQL。这话对了一半。KingbaseES本质上是一条PostgreSQL路线发展出来的数据库内核但它提供了一套完整的MySQL兼容机制。关键在于理解这套兼容机制的作用边界。所谓兼容模式不是搞一个虚拟层把MySQL的SQL“翻译”成别的方言再执行而是在语法解析器层面直接识别MySQL风格的语法。比如MySQL里常见的LIMIT 10, 20这种写法在兼容模式下能直接被KingbaseES解析器识别翻译成内核可执行的语义。这个过程发生在SQL解析阶段不是执行阶段的逐条解释。这个设计的好处是性能损耗极小坏处是兼容有边界。不是所有MySQL语法都能被识别也不是所有行为都能100%还原。我在项目里实测过大体量的普通CRUD、分页查询、聚合统计在兼容模式下跑得很顺但冷门的语法特性、依赖MySQL特定语义的写法就可能踩坑。所以“零改造”的核心思路不是“什么都不用改”而是“大部分不用改少数需要微调”。后面我会具体说哪些语法容易出现差异方便你提前排查。1.2 驱动级适配JDBC连接串怎么切换连接层改造是最容易忽略的一环。MySQL项目常用的连接方式无非JDBC、ODBC或者通过中间件。切到KingbaseES之后第一件事就是替换驱动包。实际项目中我用的方案是保留应用层代码不动把MySQL的JDBC驱动替换为KingbaseES的JDBC驱动然后在连接串上调整URL。KingbaseES的JDBC驱动在业界被称为驱动8JDBC8如果你的应用跑在Java 8及以上用这个没问题。配置示例# MySQL原始配置 jdbc:mysql://192.168.1.10:3306/order_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai # KingbaseES替换后配置 jdbc:kingbase8://192.168.1.20:54321/order_db?useUnicodetruecharacterEncodingutf8端口上要注意MySQL默认3306KingbaseES默认54321。有些项目把连接串配置放在Spring Boot的application.yml或者Nacos上改起来不费劲。有个细节值得多说一句驱动类名也要换。MySQL是com.mysql.cj.jdbc.DriverKingbaseES是com.kingbase8.Driver。如果你的项目里有显式指定driver-class-name的地方别漏了。连接串里的参数比如useSSLfalse、serverTimezoneAsia/Shanghai在KingbaseES驱动里不需要也不能照搬否则可能报参数无法识别的警告。字符集参数保留就好。如果你用的连接池是Druid或者HikariCP连接池本身不用动只是数据源配置里的driverClassName和url换掉。1.3 初始化参数与库模板的选择做对这一步少踩一半坑KingbaseES支持创建多种兼容模式的数据库。初始化实例时如果你用的是官方提供的一键安装脚本通常会默认创建ORAOracle模式、PGPostgreSQL模式和MySQL模式的模板库。要获得MySQL兼容能力创建业务库时要指定对应的模板。创建兼容MySQL的数据库语法是CREATE DATABASE order_db TEMPLATE mysql;这一步非常关键。如果库不是用mysql模板创建的后面很多MySQL专属语法都会报错哪怕你的驱动和连接串都换对了也没用。我就见过有同事忽略了模板选择结果业务启动后第一个AUTO_INCREMENT就报错排查了半天。除了模板还有几个初始化参数需要关注。KingbaseES参数文件中与控制行为相关的参数不少但迁移场景下优先确认这几个参数推荐值作用说明ora_input_trimoff控制字符串输入是否自动去空格MySQL场景建议保持默认nls_length_semanticsBYTE/CHAR影响字段长度语义按原库习惯设置default_transaction_isolationread committed事务隔离级别的默认值调整后面细说max_connections按业务峰值估算连接数上限集群环境下要配合负载均衡设置参数调整不是必须的但平不平衡直接决定你后续要不要加班。我的经验是接入业务之前先花半天把环境参数全部过一遍比业务跑起来之后逐个排查问题省时间得多。2. MySQL与KingbaseES的平台级差异数据类型与函数的隐形战场2.1 数据类型映射TINYINT、DATETIME、TEXT的去向字段类型是最容易出怪问题的地方。数据从MySQL迁到KingbaseES不是简单地把建表语句原样扔过去就行很多类型需要对应调整。先给一张我在项目中实际使用的映射表省得你一个个试MySQL类型KingbaseES兼容模式类型注意事项TINYINTSMALLINTMySQL的TINYINT(1)常被用来表示布尔值迁移后注意为逻辑判断字段添加注释INTINTEGER直接对应BIGINTBIGINT直接对应VARCHAR(n)VARCHAR(n)注意字符语义迁移前确认原库是字节还是字符TEXTTEXT直接对应DATETIMETIMESTAMP这是重点MySQL的DATETIME和TIMESTAMP语义不同迁移后统一用TIMESTAMP要留意时区问题TIMESTAMPTIMESTAMPMySQL的TIMESTAMP有2038年问题KingbaseES的TIMESTAMP范围更大DECIMAL(m,d)NUMERIC(m,d)语义一致注意精度参数保持一致BLOBBYTEA处理二进制数据应用层读取方式要测一下ENUMVARCHAR CHECK约束如果不想改代码建议保留VARCHAR并加CHECK约束注意DATETIME换成TIMESTAMP之后如果你的MySQL表里存了0000-00-00 00:00:00这种特殊值迁移时会直接报错。MySQL允许zero date但KingbaseES不允许。我当时的处理方案是在数据迁移SQL里把这类值统一替换成NULL或者改成1970-01-01 00:00:00同时通知业务方排查这些特殊值的含义。还有一个容易忽略的细节MySQL里很多表的VARCHAR长度写成VARCHAR(255)但到底按字符算还是按字节算在不同环境下结果不一样。迁移前最好逐个表确认一遍免得字段长度不够导致插入报错。2.2 高频函数的兼容实现IFNULL、DATE_FORMAT、GROUP_CONCAT函数兼容直接决定“零改造”能不能落地。业务SQL里最常用的几个MySQL函数在KingbaseES兼容模式下的表现我逐个说。IFNULL是最常用的MySQL里到处是IFNULL(a, 0)这种写法。KingbaseES兼容模式下支持IFNULL也支持COALESCE。跑过一轮发现IFNULL在兼容模式下会被解析为COALESCE执行行为和MySQL保持一致这一个基本无障碍。DATE_FORMAT也是重灾区。MySQL里格式化日期用DATE_FORMAT(now(), %Y-%m-%d)KingbaseES兼容模式下支持这个函数但需要在初始化时把date_format兼容参数打开。实际项目中我遇到过格式化之后结果返回的是VARCHAR排序时排序规则和MySQL不同导致结果顺序不一致。GROUP_CONCAT在MySQL里很常用用于把分组内的多行拼成逗号分隔的字符串。KingbaseES兼容模式也实现了GROUP_CONCAT函数功能对齐包括排序和SEPARATOR语法。不过实测下来有两个边界要注意一个是拼接结果默认长度限制MySQL的group_concat_max_len默认1024字节KingbaseES也模拟了这个限制很长的拼接会出现截断另一个是连接符和内部排序的方言差异建议迁移后对报表类的查询做一遍结果比对。其他函数NOW()、CURDATE()、SYSDATE()这类时间函数兼容模式直接支持SUBSTRING_INDEX、FIND_IN_SET这类MySQL特有函数也能识别。UUID()能用但要注意KingbaseES的UUID()返回值格式和MySQL一致都是小写带横杠。2.3 自增主键AUTO_INCREMENT在KingbaseES里的真实身份自增主键是MySQL建表最常见的能力。id INT AUTO_INCREMENT PRIMARY KEY这种写法能不能直接跑是很多人关心的。先说结论KingbaseES的MySQL兼容模式下支持AUTO_INCREMENT关键字建表语句可以直接执行。但底层实现并不是MySQL那种表级自增计数器内核会把AUTO_INCREMENT自动映射为序列Sequence来维护。这个差异带来的影响有几个第一AUTO_INCREMENT的起始值和步长。MySQL在建表时可以指定AUTO_INCREMENT1000KingbaseES兼容模式下如果你执行CREATE TABLE时带了自增值这个值会被转换成序列的起始值行为基本一致。但如果你在表已经建好之后再用ALTER TABLE ... AUTO_INCREMENT n来修改语法可以识别实际看到的效果在某些版本里需要重启连接或者刷新序列缓存才能体现。第二批量插入时自增值的消耗方式不同。MySQL在INSERT时一次取一个KingbaseES的序列有缓存机制可能出现重启后自增ID跳跃的情况。如果你的业务里有“ID必须连续”这种不合理需求趁早让产品改掉。第三LAST_INSERT_ID()函数。MyBatis Plus这类框架插入数据后要回填主键底层就是调用LAST_INSERT_ID()。兼容模式下这个函数被支持但配合AUTO_INCREMENT映射的序列使用时要在同一个连接里才生效。如果你的应用连接池配置了事务提交后换连接就可能取不到正确的ID。把连接池的druid.initialSize和maxActive配好尽量保证写操作的事务连接一致。3. 日常SQL的语法差异从LIMIT到多表更新3.1 分页查询与LIMIT语法支持兼容得最彻底的一块MySQL分页最常用的写法是LIMIT offset, row_count比如SELECT * FROM orders LIMIT 10, 30。KingbaseES兼容模式直接支持这种语法。同样支持的还有LIMIT row_count OFFSET offset的PostgreSQL风格。类似地LIMIT ?配合OFFSET ?的MyBatis分页插件比如PageHelper生成的SQL兼容模式也能解析。我在项目里就是用的PageHelper基本没有改代码。大小写、关键字顺序、嵌套子查询里的LIMIT我都测过。嵌套子查询带LIMIT的场景MySQL和KingbaseES都能跑但执行计划有差异。MySQL对物化子查询的优化策略和KingbaseES不同个别慢SQL迁移后需要重新看执行计划。3.2 UPDATE JOIN与DELETE JOIN的写法被忽略的高频差异点MySQL的UPDATE关联更新是很多人的心头好。比如UPDATE order_detail od JOIN orders o ON od.order_id o.id SET od.status o.status WHERE o.create_time 2024-01-01;这种UPDATE ... JOIN语法在KingbaseES兼容模式下不能直接跑会报语法错误。这是我在项目里遇到的最常见的语法兼容问题之一。解决方案有两个。最彻底的是改成子查询方式UPDATE order_detail od SET status ( SELECT o.status FROM orders o WHERE o.id od.order_id AND o.create_time 2024-01-01 ) WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.id od.order_id AND o.create_time 2024-01-01 );这种改法逻辑没问题但要注意如果orders表里一个order_id对应多行子查询返回多值就会报错。写之前先确认关联字段的唯一性。另一种方案是临时表方式先把关联结果抽到临时表再UPDATE关联临时表。数据量大的时候这种方式反而比子查询快但代码改动量也大。DELETE JOIN同理。MySQL的DELETE t1 FROM t1 JOIN t2 ON ...语法在KingbaseES里不支持需要改成DELETE FROM t1 WHERE EXISTS (...)。这类SQL在项目里往往藏在定时清理任务和报表模块里光靠代码扫描工具不容易发现建议迁移前后做一次全量SQL日志对比把执行过且报错的SQL捞出来统一改。3.3 特殊语句INSERT ON DUPLICATE KEY UPDATE与REPLACEMySQL的INSERT ... ON DUPLICATE KEY UPDATE非常实用主键冲突时自动转更新。KingbaseES兼容模式对这个语法的支持不同小版本行为不完全一样。我用过的版本里基本语法可以识别但要注意它依赖唯一索引来判定“duplicate”。INSERT INTO product (id, name, price) VALUES (1, 苹果, 5.5) ON DUPLICATE KEY UPDATE price VALUES(price);这个写法里VALUES(price)在新版本MySQL里已经标记为废弃KingbaseES兼容模式下也可以识别。但如果你从MySQL 8.0的写法AS new ON DUPLICATE KEY UPDATE price new.price迁移过来得先确认当前KingbaseES版本是否支持不太支持的版本需要改回旧写法。REPLACE INTO整体逻辑是“先删后插”KingbaseES兼容模式支持但同样依赖主键或唯一索引。如果有外键关联删除动作可能把子表数据一起级联删掉或者直接报错迁移前后要格外小心。还有一个和ON DUPLICATE KEY UPDATE行为相似但底层完全不同的写法MERGE INTO。如果你把MySQL的UPSERT逻辑在迁移时顺手改成MERGE语法是能跑但要小心事务行为和锁行为的变化。能不改尽量不改保持原SQL风格最稳。4. 存储过程与事务控制的迁移重点4.1 存储过程语法差异MySQL的过程体不能直接平移存储过程是“零改造”里最让人头疼的环节。MySQL的存储过程用BEGIN ... END块变量声明用DECLARE条件分支用IF ... THEN ... ELSEIF ... END IF这些在KingbaseES兼容模式下有对应支持但是细节有差异。最明显的差异是DELIMITER。在MySQL的客户端工具里写存储过程通常先DELIMITER $$把分隔符换掉再CREATE PROCEDURE ... END $$。KingbaseES的客户端比如KStudio不认DELIMITER指令提交过程体直接用CREATE OR REPLACE PROCEDURE即可块结束用/提交或者直接在客户端工具里选中过程体执行。如果你从MySQL的SQL文件导过来需要先把DELIMITER相关行去掉。变量赋值方面MySQL的SET var : 1在存储过程内可以用KingbaseES兼容模式也支持SET但如果是过程内局部变量推荐使用DECLARE加:赋值的方式。SELECT ... INTO语法两边都有但MySQL的INTO可以带多个变量KingbaseES里要确认目标变量类型匹配。游标处理的差异更大。MySQL的游标声明DECLARE cur CURSOR FOR SELECT ...在KingbaseES里也被支持但FETCH的写法和循环退出条件的NOT FOUND处理方式需要按新方言调整。我迁移一个统计报表存储过程时花了半天改游标循环。这一类切换成本高、收益低。强烈建议迁移前先盘点一下所有存储过程把复杂的报表过程、定时任务过程优先人工审核不是所有过程都能让工具自动转换。4.2 事务隔离级别与锁行为默认值不同导致的结果不一致事务隔离级别是隐藏的大坑。MySQL默认隔离级别是REPEATABLE READInnoDB在这个级别下通过MVCC实现了可重复读并且SELECT默认不加锁一致性非锁定读。KingbaseES默认隔离级别是READ COMMITTED这也是PostgreSQL系数据库的默认选择。这个差异会导致什么最典型的是一段代码在MySQL里开启了事务先SELECT一次然后另一个事务插入数据并提交再SELECT一次两次结果应该一致但同样代码在KingbaseES默认配置下第二次SELECT能看到新提交的数据结果不一致。这在报表统计、对账类业务里是致命问题。解决方案有两种一是把会话的隔离级别显式设置成REPEATABLE READSET TRANSACTION ISOLATION LEVEL REPEATABLE READ;二是调整数据库默认参数把default_transaction_isolation改成repeatable read。我在项目里采用的是第二种一次性解决避免每个应用连接还要额外执行SET语句。锁行为方面KingbaseES不像InnoDB那样有record lock、gap lock、next-key lock的完整体系但支持行级锁和表级锁。SELECT ... FOR UPDATE语法被支持行为上也是锁住匹配的行。不过FOR UPDATE配合NOWAIT和SKIP LOCKED不同版本支持程度不一样迁移后需要验证。死锁的处理也是差异点。MySQL遇到死锁会立刻回滚出错事务KingbaseES也会自动检测死锁并回滚但报错信息和触发时机略有不同。应用层如果捕获了DeadlockLoserDataAccessException这类异常要注意KingbaseES驱动抛出的异常类和MySQL不一样事务重试逻辑代码可能需要微调。4.3 字符集、排序规则与大小写敏感问题结果排序不一致的元凶字符集问题在迁移里极具隐蔽性。MySQL里utf8mb4成为标准配置既能存中文也能存表情符号。KingbaseES里对应的是UTF8编码。建库时指定ENCODING UTF8即可。但这里有个MySQL和PostgreSQL系数据库共有的经典差异字符集决定排序规则排序规则直接影响查询结果顺序。MySQL里的utf8mb4_general_ci是不区分大小写的排序时A和a视为相同。KingbaseES默认的C或POSIX排序规则对大小写敏感。于是就会出现一个很隐蔽的问题MySQL里WHERE name admin能匹配到Admin迁移到KingbaseES后却匹配不到。同样ORDER BY name的结果顺序两边也可能不一样。解决方法是建库或建表时显式指定排序规则。KingbaseES提供pg_collation可以创建不区分大小写的排序规则。我在项目里是统一建库时指定CREATE DATABASE order_db TEMPLATE mysql LC_COLLATE zh_CN.utf8;如果已经建好库可以在字段或查询级别指定COLLATE来覆盖默认行为。但要注意COLLATE是排序规则不是字符集别和SET NAMES混淆。应用连接里调用了SET NAMES utf8mb4的也要去掉KingbaseES不支持utf8mb4这个名称直接报错。用SET NAMES UTF8替代。5. 实战迁移流程从评估到切换的全过程5.1 迁移前兼容性评估如何提前预判改动量别等上线了才发现兼容性问题迁移前花两个晚上做一次全面盘点能省很多事。第一步是收集所有SQL语句。从四个渠道获取应用日志慢查询记录、MyBatis等ORM框架的SQL日志、定时任务里的存储过程、报表系统的取数SQL。汇总去重之后就是一个“待兼容SQL清单”。第二步是分类评估。我一般分四类分类判断标准处理方式绿色简单CRUD、分页查询、聚合函数不需要改动黄色使用了MySQL特有函数、特殊语法小范围改写比如IFNULL确认下、DATE_FORMAT确认参数橙色UPDATE JOIN、DELETE JOIN、REPLACE INTO需要手动改写安排专人处理红色存储过程、自定义函数、触发器需要逐个转换和功能验证第三步是拟一份“改造工作量清单”把橙色和红色项列清楚估算时间。这一步做完基本上你就能回答领导“能不能一夜切换”这个问题了。5.2 数据迁移的三种方式逻辑导出到底靠谱吗数据迁移有三个路子官方迁移工具、ETL工具、手工SQL导入导出。官方提供的KStudio迁移工具能够把MySQL的表结构、主外键、索引、数据、视图一次性搬到KingbaseES。实测下来中小规模的数据量百G以内用这个工具最省事。它会自动完成数据类型映射还会生成迁移报告里面列出每张表的迁移状态和警告信息。数据量更大的场景建议用ETL工具比如Kettle或DataX。DataX的KingbaseES writer插件在很多项目里验证过速度稳定断点续传能力也够。如果你公司有成熟的ETL平台直接扩展一个数据源就行。还有一种是手工方式MySQL导出SQL文件然后做语法适配再导入。这种方式适合数据量小、表结构简单的场景但也最容易出错。导出的CREATE TABLE语句里有ENGINEInnoDB、AUTO_INCREMENT100这些MySQL专属内容导入前要做清理。INSERT语句里如果是INSERT INTO ... VALUES多行拼一个大SQLKingbaseES也能接收但超大SQL文件导入容易超时建议用adminpack或者工具分批导入。数据迁移完成后必须做数据一致性校验。最直接的办法是两边各跑一遍计数-- MySQL SELECT COUNT(*), SUM(amount) FROM orders; -- KingbaseES SELECT COUNT(*), SUM(amount) FROM orders;关键业务表逐表比对比对结果保存下来。如果发现数字对不上先查时间类型字段的精度差异——MySQL的DATETIME支持到秒KingbaseES的TIMESTAMP支持到微秒导出导入过程可能出现精度微差再查DECIMAL精度两边如果DECIMAL(10,2)定义一致通常没问题。5.3 校验测试与灰度上线怎样算“平滑过渡”数据迁移完不等于项目切换完成应用层的回归测试才是大头。我的测试顺序是先跑核心链路比如登录、下单、支付、查询再跑报表类查询这类查询往往SQL复杂度最高最后触发定时任务把存储过程跑一遍。这中间有个细节如果原MySQL环境还有业务在跑最好先做一次“影子库存量数据导入”——把某天的全量数据导过去然后用抓包或回放工具把线上MySQL的真实SQL流量复制一份到KingbaseES环境对比两边执行结果。没有流量回放工具的话可以选几个业务高峰期手动跑一批代表性SQL逐个对比结果集。上线窗口的切换策略上我建议做“双轨并行”先让一部分只读业务切到KingbaseES观察一段时间确认稳定后再切写业务。如果业务上不允许双轨至少保留一份MySQL侧的完整备份确保快速回退可用。切换时间点尽量放在业务低峰比如周末凌晨给排查留足时间。6. 常见问题排查与避坑实录6.1 连接与驱动类问题速查报错现象可能原因解决方式No suitable driver found for jdbc:kingbase8://...驱动jar未放进lib目录或没引依赖确认驱动的groupId/artifactId引入无误检查jar包完整Connection refused端口不对或服务未启动确认端口为54321检查数据库监听状态FATAL: password authentication failed密码错误或认证方式不匹配核对初始口令调整pg_hba.conf认证方式为md5或scram-sha-256Invalid or unsupported parameter: useSSL连接串里带了MySQL专属参数去掉KingbaseES不支持的参数保留characterEncoding即可前期把所有连接串统一改掉之后我建议专门用一个半小时把每个业务模块的连接都跑一遍确认没有连接层面的隐藏问题再进入SQL兼容性测试。6.2 SQL兼容类问题速查报错或异常现象可能原因解决方式LIMIT 10, 20报语法错误数据库不是MySQL兼容模式创建确认建库时指定TEMPLATE mysqlIFNULL函数报错兼容参数未开启检查数据库参数的mysql_compat相关配置必要时升级小版本UPDATE ... JOIN语法报错兼容模式下暂不支持改写为EXISTS子查询方式REPLACE INTO报主键冲突依赖的索引缺失先核查表上的主键和唯一索引定义是否完整中文乱码连接字符集未设置连接串加characterEncodingutf8数据库初始化ENCODINGUTF8ORDER BY排序结果和MySQL不一致大小写敏感排序规则导致建表/查询时指定不区分大小写的COLLATE6.3 性能对比类问题迁移后变慢了怎么办迁移后性能下降是正常现象原因基本集中在执行计划上。MySQL的优化器和KingbaseES的优化器策略不同原本在MySQL上走索引优选的SQL到了KingbaseES可能走了别的路径。遇到性能下降的SQL先EXPLAIN ANALYZE看执行计划。常见的几个处理手段检查统计信息是否更新执行ANALYZE刷新检查表字段类型是否影响了索引生效比如隐式类型转换导致索引失效重新审视SQL里的函数运算函数包住字段会导致索引无法命中。索引方面还有个常见问题MySQL里VARCHAR字段默认排序规则不区分大小写索引可以正常命中KingbaseES里如果字段用了区分大小写的COLLATEWHERE name Admin和WHERE name admin的执行计划可能不一样因为优化器要考虑排序规则的影响。这种情况下要么给字段创建匹配的COLLATE索引要么统一排序规则。个人经验总结做了几个KingbaseES迁移项目之后我最大的感受是“零改造”是一个目标和方向而不是一句口号。真正决定项目成败的不是最后切换到KingbaseES的那个周末而是之前对SQL兼容性、函数差异、事务行为这些“隐形战场”的排查深度。前期多花的时间后期都会加倍还给你。第一次做迁移的团队建议至少留出一周时间做兼容性测试打磨。不要相信任何工具能全自动完成工具能帮你把70%的平凡工作做完剩下30%的“硬骨头”还是得靠人对业务的理解和数据库原理的把握。最后再分享一个小技巧迁移过程中把发现的每个兼容性差异点整理成文档包括报错信息、原因分析、解决方案这个文档不仅是这次项目的交付物更是下次做类似评估时的第一手资料。我第二次做评估时很多SQL看一眼就知道要不要改全靠这份积累。