侧边栏壁纸
  • 累计撰写 118 篇文章
  • 累计收到 2 条评论

从 MySQL 迁到 PostgreSQL 踩了 6 个坑,说说现在的做法

2026-5-22 / 0 评论 / 4 阅读
🤖AI摘要
本文分享了作者从MySQL迁移到PostgreSQL过程中遇到的六个问题及解决方法。问题包括自增列的差异、LIMIT和OFFSET的写法、字符串拼接、全文检索、GROUP BY的严格模式以及备份恢复。作者强调了PostgreSQL在全文检索和备份恢复方面的优势,并指出通过调整SQL语句和习惯,可以更好地适应PostgreSQL的特性。

之前一直用 MySQL,后来做了个项目需要处理地理数据和复杂查询,听说 PostgreSQL 这方面更顺手,就动了迁移的心思。迁移过程比我想的折腾不少。

第一个碰到的是自增主键。MySQL 写惯了:

id INT AUTO_INCREMENT PRIMARY KEY

拿到 PG 里直接报错。PG 用 SERIAL:

id SERIAL PRIMARY KEY

或者标准写法 GENERATED AS IDENTITY。SERIAL 背后会自动建一个序列对象,GENERATED AS IDENTITY 更严格一点,PG 会完全接管序列,不让你手动插入冲突值。

翻页也有区别。MySQL 的写法:

SELECT * FROM users LIMIT 10 OFFSET 20;

PG 也吃这套,但它还支持 SQL 标准的写法:

SELECT * FROM users OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

PG 13 以下有个坑——FETCH NEXT 后面不能跟参数,只能写固定数字,后来版本才修了。

字符串拼接一开始也让我懵了一会儿。MySQL 用 CONCAT():

SELECT CONCAT(first_name, ' ', last_name);

PG 用 ||:

SELECT first_name || ' ' || last_name;

在 MySQL 里 || 是逻辑或,第一次在 PG 里写 SELECT 1 || 2 出了个完全不一样的结果,查了半天才反应过来。

全文检索这块,PG 确实更强。MySQL 的全文检索只支持 MyISAM 和 InnoDB,中文分词基本靠第三方。PG 原生支持 tsvector 和 tsquery:

SELECT * FROM articles
WHERE to_tsvector('simple', title) @@ to_tsquery('simple', 'postgresql & migration');

为了中文分词我还配了 SCWS 插件,配置过程有点折腾,但效果比 MySQL 好太多。

GROUP BY 的严格模式也坑了我一次。MySQL 允许 SELECT 里出现不在 GROUP BY 中的非聚合列:

SELECT id, name, COUNT(*) FROM orders GROUP BY status;

PG 直接报错,要求 SELECT 里的非聚合列必须都在 GROUP BY 里。要么把 id 和 name 加进去,要么用 MAX() 之类的聚合函数包一下。这个习惯改过来之后,SQL 写得更严谨了。

备份工具也不太一样。MySQL 用 mysqldump,PG 对应用 pg_dump:

pg_dump -U postgres dbname > backup.sql

pg_dump 支持更多格式:纯 SQL、tar、自定义压缩。自定义格式可以用 pg_restore 选择性恢复某张表,这在 MySQL 里不太方便:

pg_dump -U postgres -Fc dbname > backup.dump
pg_restore -U postgres -d dbname -t users backup.dump

而且 pg_restore 可以指定并行度,大库恢复快很多。

从 MySQL 迁移到 PG,初期确实不习惯,语法和工具链差异不小。但用了一段时间之后,PG 的标准化程度和扩展能力(JSONB、全文检索、GIS)确实值回迁移成本。我前后折腾了两周才把所有业务流程跑顺,现在用着挺顺手。

评论一下?

OωO
取消