首页技术专题博客目录我的收藏关于与联系

数据库迁移的噩梦:从 MySQL 到 PostgreSQL

公司决定把数据库从 MySQL 迁移到 PostgreSQL,说是性能更好、功能更强。迁移花了 3 个月,踩了无数坑。这篇文章记录一下迁移过程和遇到的问题。

为什么迁移?

公司决定迁移数据库,理由是 PostgreSQL 性能更好、功能更强、更符合标准。听起来很有道理,我们就开始迁移了。

但迁移后发现,大部分理由都是理论上的。实际用下来,性能提升不明显,但迁移成本很高。

迁移前的准备

迁移前,我们做了这些准备:

  • 梳理所有数据库表结构和数据
  • 分析 SQL 语句,找出不兼容的地方
  • 准备迁移脚本和回滚方案
  • 搭建测试环境,先测试迁移

但实际迁移时,还是遇到了很多问题。

第一个坑:数据类型不兼容

MySQL 和 PostgreSQL 的数据类型不完全兼容。比如:

  • MySQL 的 TEXT 在 PostgreSQL 里也是 TEXT,但长度限制不同
  • MySQL 的 DATETIME 在 PostgreSQL 里是 TIMESTAMP
  • MySQL 的 BOOLEANTINYINT(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_dumppg_restore 迁移数据。但数据量大,迁移很慢。我们用了并行迁移,才快了一些。

第二阶段:代码迁移

把所有 SQL 语句都改了一遍,适配 PostgreSQL。这个过程最麻烦,花了很多时间。

第三阶段:测试

在测试环境测试了很长时间,发现了很多问题。修复后,再测试,直到没问题。

第四阶段:上线

上线时,做了灰度发布。先迁移一部分数据,没问题再全部迁移。整个过程花了 3 个月。

如果重新开始

如果重新迁移数据库,我会:

  • 先评估迁移的必要性,不要盲目迁移
  • 做好充分的准备,包括数据备份和回滚方案
  • 在测试环境充分测试,不要急于上线
  • 做好监控和告警,及时发现问题

总结

数据库迁移是个大工程,不是简单的数据迁移,而是整个系统的改造。

如果你们的项目也在考虑迁移数据库,建议先评估一下迁移的必要性和成本。如果 MySQL 够用,就不要迁移。如果一定要迁移,也要做好充分的准备。

我们迁移花了 3 个月,但性能提升不明显。如果重新选择,我可能会建议不迁移,或者用其他方案。

评论区