总体对比(速览)
-
相似处:都支持 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
DATETIME
vs 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
)、并为大表规划分区。