为什么要迁移?
越来越多的团队选择从 MySQL 迁移到 PostgreSQL,主要驱动力包括:
-
需要 JSONB、地理空间、数组等高级数据类型
-
业务规模增长,需要更强的并发处理能力(MVCC)
-
复杂查询性能瓶颈
-
更严格的 SQL 标准合规要求
本文总结迁移过程中的关键步骤和常见坑,帮助你少走弯路。
一、语法差异速查表
| 场景 | MySQL | PostgreSQL |
|---|---|---|
| 字符串拼接 | CONCAT(a, b) |
`a |
| 自增主键 | AUTO_INCREMENT |
SERIAL 或 GENERATED ALWAYS AS IDENTITY |
| 限制行数 | LIMIT 10 |
LIMIT 10(相同) |
| 日期函数 | NOW() |
NOW()(相同) |
| 字符串比较 | 默认大小写不敏感 | 默认大小写敏感 ⚠️ |
| 布尔值 | 1 / 0 |
TRUE / FALSE |
| 反引号字段名 | field |
"field"(双引号) |
| GROUP BY | 允许非聚合字段 | 必须严格聚合 ⚠️ |
二、最常踩的三个坑
坑 1:字符串大小写敏感
MySQL 默认不区分大小写,PostgreSQL 默认区分。
sql
-- MySQL 中返回结果
SELECT * FROM users WHERE name = 'alice'; -- 能匹配 'Alice'
-- PostgreSQL 中不返回(大小写严格匹配)
SELECT * FROM users WHERE name = 'alice'; -- 匹配不到 'Alice'
-- PostgreSQL 正确写法
SELECT * FROM users WHERE LOWER(name) = LOWER('alice');
-- 或者使用不区分大小写的操作符
SELECT * FROM users WHERE name ILIKE 'alice';
坑 2:GROUP BY 严格模式
sql
-- MySQL 中可以运行(宽松模式)
SELECT name, age, COUNT(*) FROM users GROUP BY name;
-- PostgreSQL 报错:age 必须出现在 GROUP BY 或聚合函数中
-- 正确写法:
SELECT name, MAX(age), COUNT(*) FROM users GROUP BY name;
坑 3:自增主键语法不同
sql
-- MySQL
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255)
);
-- PostgreSQL(推荐现代写法)
CREATE TABLE posts (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
title VARCHAR(255)
);
-- PostgreSQL(兼容旧写法)
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(255)
);
三、迁移工具推荐
pgloader(推荐)
开源工具,支持从 MySQL 直接迁移到 PostgreSQL,自动转换数据类型。
bash
# 安装
sudo apt install pgloader
# 执行迁移
pgloader mysql://user:pass@localhost/mydb \
postgresql://user:pass@localhost/mydb
pgloader 会自动:
-
转换
AUTO_INCREMENT→SERIAL -
转换
TINYINT(1)→BOOLEAN -
转换字符集和排序规则
AWS DMS
适合生产环境的在线迁移,支持最小停机时间的持续同步,适合数据量大、业务不能中断的场景。
四、迁移后的性能调优
迁移完成后,需要针对 PostgreSQL 做专项优化:
sql
-- 1. 更新统计信息(迁移后必做)
ANALYZE;
-- 2. 检查缺失索引
SELECT schemaname, tablename, attname, n_distinct, correlation
FROM pg_stats
WHERE tablename = 'your_table';
-- 3. 查看慢查询
SELECT query, calls, total_time, mean_time
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;
五、迁移检查清单
- 字符串比较逻辑已改为大小写敏感
- GROUP BY 语句已检查聚合合规性
- AUTO_INCREMENT 已替换为 SERIAL 或 IDENTITY
- 反引号字段名已改为双引号或去掉引号
- BOOLEAN 字段已从 0/1 改为 TRUE/FALSE
- 执行 ANALYZE 更新统计信息
- 索引已重建并验证
- 应用层连接串已更新
总结
MySQL 到 PostgreSQL 的迁移不是一蹴而就的工作,语法差异、大小写敏感和聚合规则是最常见的问题点。建议先在测试环境用 pgloader 做一次完整迁移,跑通所有 SQL,再逐步切换生产环境。迁移的短期成本换来的是长期更强大的功能和并发能力,对于成长中的业务是值得投入的。