总体对比(速览)
-
相似处:都支持 SQL 标准的大部分 DDL/DML(CREATE TABLE/INDEX、SELECT、JOIN、GROUP BY、事务等)。很多基本语法
SELECT ... FROM ... WHERE ...、JOIN、GROUP BY基本一致。 -
主要不同点(高频影响):
-
标识符引用:MySQL 用反引号
`col`;Postgres 用双引号"col"(通常不需要引用,除非大小写/特殊字符)。 -
自增主键:MySQL
AUTO_INCREMENT;Postgres 用SERIAL/BIGSERIAL(老)或标准GENERATED {ALWAYS|BY DEFAULT} AS IDENTITY(推荐)。 -
字段类型:MySQL 有
TINYINT、ENUM等;Postgres 有更强的类型系统(SERIAL、TEXT、JSONB、ARRAY、UUID、TIMESTAMP WITH(OUT) TIME ZONE等),没有 unsigned。 -
字符串连接:MySQL
CONCAT(a,b);Postgresa || b或也可用concat()。 -
NULL/函数:MySQL
IFNULL(x,y)-> PostgresCOALESCE(x,y)。MySQLIF(expr, true, false)-> PostgresCASE WHEN ... THEN ... ELSE ... END或filter/bool表达式。 -
upsert:MySQL
INSERT ... ON DUPLICATE KEY UPDATE;PostgresINSERT ... ON CONFLICT (...) DO UPDATE SET ...(更强)。 -
分区:Postgres 自 v10+ 支持 declarative partitioning(RANGE/LIST/HASH);语法和实现与 MySQL(InnoDB 分区)不同,细节不一样。
-
存储过程/函数:MySQL 用
DELIMITER与CREATE PROCEDURE/CREATE FUNCTION;Postgres 用CREATE FUNCTION(或CREATE PROCEDURE自 v11 起)并用LANGUAGE plpgsql,语法不同(不需要DELIMITER)。 -
定时任务:MySQL 有
EVENT(内置事件调度器);Postgres 没有内置 scheduler,需要cron、pg_cron、pgAgent等扩展或外部 cron 调用psql。 -
索引类型:Postgres 支持 btree、hash、GIN、GiST、BRIN、SP-GiST 等,能针对 jsonb、全文、trigram 做专用索引。
-
事务与锁:两者都支持事务;但 Postgres 的 MVCC、行级可见性、VACUUM/autovacuum 等机制和细节更重要(需要维护统计信息)。
-
配置/管理:Postgres 倾向于通过配置文件、扩展(extensions)与维护任务(VACUUM、ANALYZE)来管理性能。
-
命名 & 类型 & 语法差异常见对照表
1) 表和数据类型:从 MySQL 转到 PostgreSQL 的典型写法
MySQL 示例:
Postgres 等价(推荐):
或者用 CHECK 替代 ENUM:
注意:
-
Postgres 推荐
timestamptz(timestamp with time zone)用于表示绝对时间,除非你确有理由用无时区timestamp. -
SERIAL是便利语法,会创建序列;IDENTITY更符合 SQL 标准且行为更明确。
2) 基础 SELECT / JOIN / LIMIT 差异与范例
MySQL:
Postgres 基本相同(几乎不变):
注意:
-
Postgres 支持
ILIKE(case-insensitive LIKE),MySQL 可用COLLATE或LOWER. -
字符串连接多用
||:first_name || ' ' || last_name。
3) INSERT ... ON CONFLICT(Upsert) vs MySQL 的 ON DUPLICATE KEY
MySQL:
Postgres:
EXCLUDED 表示插入时遇到冲突的那行(等同 MySQL 的 VALUES())。
4) 存储过程 / 函数(MySQL 的 DELIMITER -> Postgres 的 plpgsql)
MySQL 存储过程通常:
Postgres(函数):
如果需要事务控制(BEGIN/COMMIT)内部,Postgres FUNCTION 不能包含事务控制语句(COMMIT/ROLLBACK),但 PROCEDURE(Postgres v11+)可以:
常见模式:函数返回 SETOF 或复合类型,用于复杂查询、返回表格。
示例:函数带返回值
5) 触发器(Triggers)
MySQL:
Postgres(触发器函数 + CREATE TRIGGER):
注意:
-
Postgres 的触发器函数必须返回
NEW(对于 BEFORE INSERT/UPDATE)或NULL(删除行),或返回OLD等。 -
Postgres 支持
FOR EACH ROW与FOR EACH STATEMENT。
6) 定时任务(Scheduler)
MySQL 有 EVENT。Postgres 没有内建 scheduler(到目前为止),常见做法:
-
使用操作系统的
cron调用psql -c "SELECT my_task();". -
使用扩展
pg_cron(需要安装扩展并在postgresql.conf加载): -
使用
pgAgent(pgAdmin 附带的任务调度器)。 -
使用外部任务队列(如 rabbitmq + worker)或应用层 Cron。
给出 cron 外部示例(Linux crontab):
7) 事务与隔离级别
Postgres 支持标准事务与隔离级别(READ COMMITTED 默认、REPEATABLE READ、SERIALIZABLE):
保存点(Savepoint):
注意 Postgres 的 MVCC:事务不会阻塞读(默认),但写冲突和冻结(VACUUM)需要关注。
8) 索引优化(常见技巧与示例)
Postgres 支持多种索引类型与高级技巧:
-
常规 B-Tree(默认):
-
部分索引(partial index):对经常查询的子集加索引,节省空间
-
表达式索引(expression index):对函数结果建索引
-
覆盖索引(INCLUDE)——类似 MySQL 的 covering index:
-
GIN(用于 jsonb/数组/全文):
-
Trigram 索引(pg_trgm extension)用于模糊搜索:
-
BRIN(大型顺序表,廉价):
性能诊断:
-
使用
EXPLAIN ANALYZE <query>查看实际执行计划和时间。 -
使用
pg_stat_statements扩展追踪慢查询。 -
记得
ANALYZE(或 VACUUM ANALYZE)以更新统计信息,让优化器正确选择索引。
清理:
-
VACUUM和AUTOVACUUM在 Postgres 中必不可少,尤其有大量 UPDATE/DELETE 时要注意表 bloat。
9) 分区表(Declarative Partitioning 示例)
Postgres 现代分区(推荐):
List 分区:
注意:
-
分区键应在查询的 WHERE 子句中被使用,这样 planner 能做分区裁剪(pruning)。
-
可以为分区单独创建索引(自 Postgres 11+ 支持分区继承索引等)。
-
Postgres 支持
attach partition用于后期添加历史数据分区。
10) EXPLAIN/性能工具示例
看输出,观察是否走索引、是否有排序/HashAggregate、是否有重大 I/O。
建议启用并查询统计扩展:
11) 事务隔离下的常见坑与迁移注意点
-
MySQL 的默认隔离级别在 InnoDB 通常是
REPEATABLE READ(但行为与 Postgres 不完全相同,MySQL 的 gap locks 有不同效果)。Postgres 默认是READ COMMITTED。 -
MySQL 的
SELECT ... FOR UPDATE锁行为与 Postgres 的行级锁类似,但细节要注意(Postgres 不会自动锁定扫描范围之外的 gap)。 -
无符号(unsigned):MySQL 有 unsigned,但 Postgres 没有,迁移时需检查上限,可能要用
bigint或约束。 -
时间类型:MySQL
DATETIMEvs Postgrestimestamp with time zone— 需要在迁移时核对时区逻辑。
12) 示例:综合案例 — 从 MySQL 查询改写到 Postgres + 优化
MySQL 查询(示例):
Postgres 等价并优化:
优化要点:
-
对
posts建复合索引(user_id, created_at)有助于按 user_id 筛选并利用 created_at 范围。 -
EXPLAIN ANALYZE看是否走索引;可能需要调整统计或重建索引。
13) 管理与维护补充(重要但容易忽视)
-
VACUUM/ANALYZE:Postgres 需要清理死行并统计表格统计信息。autovacuum通常开启,但需监控。 -
pg_stat_activity可用于查看当前连接与锁。 -
长事务会阻碍 VACUUM;确保不要长时间持有 open transaction。
-
备份/恢复:Postgres 常用
pg_dump(逻辑)和pg_basebackup(物理)或工具pgBackRest、Barman。 -
字符集:Postgres 数据库在创建时指定
ENCODING(如 UTF8)和LC_COLLATE/LC_CTYPE(排序/大小写规则)。
14) 常见迁移片段(MySQL -> Postgres)
-
把
AUTO_INCREMENT->GENERATED ... AS IDENTITY或SERIAL。 -
把
ENUM->CREATE TYPE ... AS ENUM(或者 CHECK)。 -
把
TINYINT(1)变成boolean。 -
把
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4移除,确保数据库 UTF8。 -
ON DUPLICATE KEY UPDATE->ON CONFLICT DO UPDATE. -
转义标识符:从
`name`改成"name"或直接name(小写)。
15) 一些实用的小技巧和常见命令(psql 客户端)
-
登录:
psql -h host -U user -d dbname -
列表表:
\dt -
查看表结构:
\d tablename -
执行 SQL 文件:
psql -d dbname -f script.sql -
退出:
\q
16) 快速参考:常用函数对照
示例合集(把核心都放一起,便于复制执行)
总结与建议
-
如果你来自 MySQL:最重要的是适应 类型差异(无 unsigned)、标识符引用、SERIAL/IDENTITY、ON CONFLICT、trigger/func 语法、以及 PostgreSQL 的维护(VACUUM/ANALYZE/autovacuum)。
-
性能方面学会用
EXPLAIN ANALYZE、pg_stat_statements、并熟悉多种索引(GIN/BRIN/GIN_TRGM/GiST)——Postgres 在复杂查询/JSON/全文搜索上比 MySQL 更灵活,但也更依赖正确索引和维护。 -
调度任务:Postgres 没有内置 scheduler,推荐
pg_cron或外部 cron/pgAgent。 -
开发流程:多使用
psql的元命令(如\d、\dt)、并为大表规划分区。
