PostgreSQL vs MySQL:实际项目中的选择

最近两个项目分别用了 PostgreSQL 和 MySQL,对比一下感受。

功能对比

功能PostgreSQLMySQL
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,没必要换。

数据库选型只是第一步,更重要的是用好它。索引设计、查询优化、监控告警,这些才是关键。