PostgreSQL vs MySQL:实际项目中的选择
最近两个项目分别用了 PostgreSQL 和 MySQL,对比一下感受。
功能对比
| 功能 | PostgreSQL | MySQL |
|---|---|---|
| JSON 支持 | 原生 JSONB,支持索引 | JSON 类型,索引较弱 |
| 全文搜索 | 内置,中文需要分词插件 | 内置,一般 |
| 地理位置类型 | PostGIS 扩展,很强 | 基本支持 |
| 窗口函数 | 完整支持 | 8.0 后支持 |
| 并发控制 | MVCC,无锁读 | MVCC,有差距 |
| 事务隔离 | 支持全部级别 | 默认 REPEATABLE READ |
PostgreSQL 用得爽的地方
JSONB
存 JSON 不用序列化,直接当字段用:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
attrs JSONB
);
-- 查询 JSON 内字段
SELECT * FROM products WHERE attrs->>'color' = 'red';
-- 给 JSON 字段建索引
CREATE INDEX idx_attrs_color ON products ((attrs->>'color'));
我们有个商品属性系统,用 JSONB 存动态属性,省了建一堆字段。
数组类型
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
tags TEXT[]
);
-- 查询包含某标签的文章
SELECT * FROM posts WHERE 'vue' = ANY(tags);
-- 数组聚合
SELECT array_agg(name) FROM users WHERE team_id = 1;
CTE (Common Table Expression)
复杂查询用 CTE 写起来很清晰:
WITH monthly_sales AS (
SELECT
DATE_TRUNC('month', created_at) AS month,
SUM(amount) AS total
FROM orders
GROUP BY month
),
ranked AS (
SELECT
month,
total,
LAG(total) OVER (ORDER BY month) AS prev_total
FROM monthly_sales
)
SELECT
month,
total,
(total - prev_total) / prev_total * 100 AS growth_rate
FROM ranked;
MySQL 用得爽的地方
简单项目上手快
# 安装
brew install mysql
# 创建数据库
CREATE DATABASE myapp;
# 搞定
PostgreSQL 的配置项多,新手容易晕。
生态成熟
ORM、连接池、监控工具,MySQL 都有一堆选择。云服务商对 MySQL 的支持也更完善。
读写分离
MySQL 主从复制配置简单,很多云数据库一键开启。PostgreSQL 也可以,但配置起来麻烦点。
存储过程
虽然现在不推荐用存储过程,但有些老项目确实依赖这个。MySQL 的存储过程语法更接近直觉。
踩过的坑
PostgreSQL
1. 连接数限制
默认最大连接数 100,不够用。改 max_connections 要重启。
后来用了 PgBouncer 做连接池:
# pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25
2. VACUUM
MVCC 的代价是更新会产生死元组,需要 VACUUM 清理。虽然有 autovacuum,但高写入场景还是需要调优。
MySQL
1. InnoDB 锁
大批量更新容易锁表,得用分批处理:
def batch_update():
while True:
rows = db.execute("SELECT id FROM items WHERE status = 'pending' LIMIT 1000")
if not rows:
break
ids = [r.id for r in rows]
db.execute(f"UPDATE items SET status = 'done' WHERE id IN ({','.join(ids)})")
2. 字符集
一定要显式设置 utf8mb4,默认的 utf8 是阉割版:
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
选型建议
| 场景 | 推荐 |
|---|---|
| 简单 CRUD、快速开发 | MySQL |
| 复杂查询、数据分析 | PostgreSQL |
| 大量 JSON 数据 | PostgreSQL |
| 地理位置应用 | PostgreSQL + PostGIS |
| 传统企业应用 | MySQL |
| 高并发读写分离 | MySQL |
迁移成本
从 MySQL 迁移到 PostgreSQL:
- DDL 语法有差异
- 自增主键写法不同
- 部分函数名不一样
建议用 pgloader 或 AWS DMS,比自己写脚本省事。
总结
没有绝对的优劣,看需求选。
我现在默认选 PostgreSQL,因为 JSON 支持好、扩展性强。但如果是小项目、团队熟悉 MySQL,没必要换。
数据库选型只是第一步,更重要的是用好它。索引设计、查询优化、监控告警,这些才是关键。