为什么迁移?
公司决定迁移数据库,理由是 PostgreSQL 性能更好、功能更强、更符合标准。听起来很有道理,我们就开始迁移了。
但迁移后发现,大部分理由都是理论上的。实际用下来,性能提升不明显,但迁移成本很高。
迁移前的准备
迁移前,我们做了这些准备:
- 梳理所有数据库表结构和数据
- 分析 SQL 语句,找出不兼容的地方
- 准备迁移脚本和回滚方案
- 搭建测试环境,先测试迁移
但实际迁移时,还是遇到了很多问题。
第一个坑:数据类型不兼容
MySQL 和 PostgreSQL 的数据类型不完全兼容。比如:
- MySQL 的
TEXT在 PostgreSQL 里也是TEXT,但长度限制不同 - MySQL 的
DATETIME在 PostgreSQL 里是TIMESTAMP - MySQL 的
BOOLEAN用TINYINT(1),PostgreSQL 有真正的BOOLEAN - MySQL 的
JSON在 PostgreSQL 里是JSONB
我们写了个脚本,自动转换数据类型。但有些复杂的类型,还是要手动改。
第二个坑:SQL 语法差异
MySQL 和 PostgreSQL 的 SQL 语法有很多差异:
- MySQL 的
LIMIT可以用变量,PostgreSQL 不行 - MySQL 的字符串拼接用
CONCAT,PostgreSQL 用|| - MySQL 的日期函数和 PostgreSQL 不同
- MySQL 的
GROUP BY规则和 PostgreSQL 不同
我们花了很长时间,把所有 SQL 语句都改了一遍。有些复杂的查询,改起来很麻烦。
第三个坑:索引和约束
MySQL 和 PostgreSQL 的索引和约束也有差异:
- MySQL 的索引名可以重复,PostgreSQL 不行
- MySQL 的外键约束检查时机和 PostgreSQL 不同
- MySQL 的全文索引和 PostgreSQL 不同
我们重新创建了所有索引和约束,花了不少时间。
第四个坑:存储过程和函数
我们的 MySQL 数据库里有很多存储过程和函数,但 MySQL 和 PostgreSQL 的语法完全不同。
MySQL 用 DELIMITER,PostgreSQL 用 $$。MySQL 的变量用 @,PostgreSQL 用 $1, $2。
我们花了很长时间,把所有存储过程和函数都重写了一遍。有些复杂的逻辑,重写起来很麻烦。
第五个坑:字符集和编码
MySQL 默认用 utf8,但 utf8 不是真正的 UTF-8,是 UTF-8 的子集。PostgreSQL 默认用 UTF8,是真正的 UTF-8。
迁移时,有些特殊字符会乱码。我们花了很长时间,才把所有字符集都统一了。
第六个坑:性能问题
迁移后,发现有些查询变慢了。原因是:
- PostgreSQL 的查询优化器和 MySQL 不同
- 索引策略不同,有些索引在 PostgreSQL 里不生效
- 连接池配置不同,需要重新调优
我们花了很长时间,重新优化了查询和索引,才恢复到原来的性能。
迁移过程
迁移过程分几个阶段:
第一阶段:数据迁移
用 pg_dump 和 pg_restore 迁移数据。但数据量大,迁移很慢。我们用了并行迁移,才快了一些。
第二阶段:代码迁移
把所有 SQL 语句都改了一遍,适配 PostgreSQL。这个过程最麻烦,花了很多时间。
第三阶段:测试
在测试环境测试了很长时间,发现了很多问题。修复后,再测试,直到没问题。
第四阶段:上线
上线时,做了灰度发布。先迁移一部分数据,没问题再全部迁移。整个过程花了 3 个月。
如果重新开始
如果重新迁移数据库,我会:
- 先评估迁移的必要性,不要盲目迁移
- 做好充分的准备,包括数据备份和回滚方案
- 在测试环境充分测试,不要急于上线
- 做好监控和告警,及时发现问题
总结
数据库迁移是个大工程,不是简单的数据迁移,而是整个系统的改造。
如果你们的项目也在考虑迁移数据库,建议先评估一下迁移的必要性和成本。如果 MySQL 够用,就不要迁移。如果一定要迁移,也要做好充分的准备。
我们迁移花了 3 个月,但性能提升不明显。如果重新选择,我可能会建议不迁移,或者用其他方案。
评论区