这事儿其实挺有意思的。我有个朋友在一家国企做数据库运维,去年他们集团下了死命令,所有系统必须在两年内完成国产化替代。他负责的核心业务系统底层跑的是 MySQL,目标数据库换成了瀚高。刚开始他以为就是个简单的数据搬家,把表结构导过去,数据灌进去,改改连接串就完事了。结果一上手才发现,这事儿远没那么简单,坑一个接一个,光兼容性问题就折腾了小半个月。后来他跟我吐槽,这哪是迁移,简直是把数据库从里到外重新学了一遍。

第一个大坑是数据类型。MySQL 和瀚高虽然都支持 SQL 标准,但细节差异能把人逼疯。比如 MySQL 里常用的 TINYINT,瀚高里根本没有。瀚高是基于 PostgreSQL 内核开发的,数据类型更接近 PG 那套,TINYINT 只能用 SMALLINT 或自定义 DOMAIN 来模拟。更头疼的是日期时间类型,MySQL 的 DATETIME 和 TIMESTAMP 行为差别很大,瀚高里又有自己的一套规则。我朋友的一个表存的是订单时间,MySQL 用的是 DATETIME,迁移到瀚高后程序跑着跑着就报错,查了半天才发现是时区转换的问题。MySQL 的 DATETIME 不带时区信息,但瀚高的 TIMESTAMP 默认带时区,导致写入和读取的时间对不上。
第二个坑是字符集和排序规则。很多老系统在 MySQL 里用的是 utf8mb4 字符集,但瀚高默认的字符集是 UTF8,名字相近却实现不同。更麻烦的是排序规则,MySQL 里很多字段用了 utf8mb4generalci 或 utf8mb4unicodeci,瀚高里对应的规则名完全不同。我朋友的系统有个用户表,按用户名排序的功能经常用,迁移后排序结果全乱了。后来只能一个字段地改排序规则,还得在应用层做额外的排序处理,工作量直接翻倍。
存储过程和函数的迁移更是噩梦。MySQL 的存储过程语法和瀚高差异巨大,尤其是变量声明、游标使用、异常处理这些地方。MySQL 用 DECLARE 声明变量,瀚高也用 DECLARE 但语法细节不同;MySQL 的游标用 FETCH NEXT FROM,瀚高用 FETCH FROM;MySQL 的异常处理用 DECLARE … HANDLER,瀚高用 EXCEPTION 块。我朋友有个存储过程,里面嵌套了三层游标循环,还用了多个条件判断和异常处理,手动改了一遍又一遍,每次跑都报新的错。于是他把复杂的存储过程重写成应用层的 Java 代码,虽然性能稍差,但至少能稳定运行。
索引和性能优化也是隐藏的炸弹。MySQL 的索引类型相对简单,主要是 B+树和哈希索引,而瀚高支持更多类型,比如 GiST、GIN、BRIN。迁移时,很多人图省事直接保留原来的索引定义,结果查询性能不如 MySQL。我朋友的系统有个全文搜索功能,MySQL 用的是 FULLTEXT 索引,迁移到瀚高后直接用了 GIN 索引,但参数没调好,搜索速度慢了好几倍。后来他花了三天时间研究瀚高的全文搜索配置,调整了分词器、权重和排名算法,才把性能追回来。而且瀚高的索引维护成本更高,重建索引的时间比 MySQL 长不少,只能在业务低峰期进行。
应用层的连接配置也得大改。MySQL 的 JDBC 驱动和瀚高的高斯 JDBC 驱动,连接字符串写法完全不同,连接池的配置参数也不一样。我朋友的系统用的是 Druid 连接池,原来针对 MySQL 优化的参数(如 maxActive、initialSize、testOnBorrow)在瀚高里需要重新调。最坑的是,瀚高的驱动对某些 SQL 语句的解析方式不同,导致一些在 MySQL 里跑得好的预编译语句,在瀚高里报参数绑定错误。他排查了两天才发现,原来是 SQL 里有个特殊字符,MySQL 的驱动自动转义了,但瀚高的驱动没有处理,只能在应用层手动加转义逻辑。
事务隔离级别和锁机制的差异直接影响高并发场景。MySQL 默认的隔离级别是 REPEATABLE READ,而瀚高默认是 READ COMMITTED。我朋友的系统有个秒杀功能,MySQL 下用 REPEATABLE READ 配合间隙锁能防止幻读。迁移到瀚高后,默认的 READ COMMITTED 级别下间隙锁不生效,出现了不少超卖现象。他被迫在关键事务里显式设置隔离级别为 SERIALIZABLE,但并发性能随之下降。于是只能重新设计秒杀逻辑,改用分布式锁和乐观锁来保证数据一致性,代码重构了一大半。
备份和恢复策略也得重新规划。MySQL 的备份工具 mysqldump 和 XtraBackup 我朋友用得滚瓜烂熟,但瀚高的备份工具是 gsdump 和 gsbasebackup,参数和用法完全不一样。他第一次用 gsdump 做全量备份,忘记加 --no-owner 参数,备份文件里包含了数据库用户的 owner 信息,恢复时因为用户名不匹配直接报错。还有一次做增量备份,他按 MySQL 的习惯每天全量一次、每小时一次 binlog 备份,但瀚高的 WAL 日志管理方式不同,频繁备份反而导致磁盘写爆。后来改成每天全量一次、每 6 小时一次增量备份,才把备份恢复流程跑通。
运维监控这块也得从头来。MySQL 有成熟的 Prometheus+mysqldexporter 监控方案,我朋友早已搭好,各种指标一目了然。但瀚高的监控生态不够完善,官方提供的 exporter 功能有限,很多自定义指标只能自己写脚本采集。他想监控瀚高的活跃连接数和慢查询数量,找了一圈没有现成方案,只能自己写 Shell 脚本定时执行 SQL 采集数据,再推送到 Prometheus。而且瀚高的慢查询日志格式与 MySQL 不同,分析工具也不兼容,他先用 Python 写了个解析脚本,把日志转成统一格式,才能接入原有的告警系统。
说一句,迁移不是终点,而是新的起点。我朋友的系统上线后,又陆续发现一些隐藏问题,比如某些 SQL 在瀚高下执行计划选择不当导致查询超时;瀚高的自动清理机制没有 MySQL 那么激进,导致表膨胀影响性能。他每个月都要花时间做性能调优和参数调整。但好处是,瀚高毕竟是国产数据库,遇到问题可以直接找原厂技术支持,反馈速度比 MySQL 社区快多了。而且瀚高对 PostgreSQL 生态兼容得很好,很多 PG 的扩展工具和第三方组件都能直接使用。如果你们也在做类似迁移,建议先在非核心业务上练手,摸透兼容性问题再动核心系统,别像我朋友那样一上来就搞大迁移,半夜被电话叫醒的感觉真的不好受。


