MySQL、PostgreSQL(PG)与 Oracle:区别、SQL 对照与选型指南
2026-10-12 09:40:00

适合人群:会写基本 CRUD、准备做项目选型或刚接手多数据库项目的 Java 开发者。

先说结论:**没有“最好的数据库”,只有最匹配当前约束的数据库。**普通业务系统优先考虑 MySQL;复杂数据模型、GIS、JSONB 或复杂分析需求突出时重点评估 PostgreSQL;客户既有 Oracle 体系或对企业级治理、高可用有明确要求时使用 Oracle。选型时,现有生态和团队熟悉度通常比“某项参数更高”更重要。

一、先用一张图建立全局认识

MySQL、PostgreSQL(通常简称 PG)和 Oracle 都是关系型数据库:都有表、SQL、索引、事务、锁、备份与高可用方案。它们不是“一个能做、另一个不能做”的简单关系,真正不同的是设计优先级、默认行为和生态成熟的方向。

图1:MySQL、PostgreSQL 与 Oracle 的典型生态定位

把它们想成三种不同取舍的工具:

  • MySQL:把常见 Web 业务做得足够成熟、足够普及。以 InnoDB 为默认引擎后,事务、行锁、MVCC 都已经是标准能力;资料、云服务、招聘市场和运维工具也最丰富。
  • PostgreSQL:更强调 SQL 标准、丰富的数据类型与可扩展性。除了关系数据,还常被用于 JSON 文档、全文检索、空间数据(PostGIS)及复杂报表等场景。
  • Oracle Database:长期服务于金融、电信、政务等关键系统,企业级权限、审计、备份恢复和高可用产品线成熟;相应地,采购、许可和专业运维的门槛也更高。

不要把“开源”理解成“没有成本”。数据库的总成本还包括迁移、备份恢复、监控、故障演练、性能调优和团队学习。反过来也不要因为 Oracle 功能强大,就在一个普通后台管理系统里引入过重的复杂度。

二、核心差异速查表

维度 MySQL PostgreSQL(PG) Oracle Database
开源 / 授权 社区版可用,另有商业支持 PostgreSQL License,开源 商业产品为主,提供 Free / XE 等受限版本
常见定位 Web 业务、SaaS、常规 OLTP 复杂业务、分析、扩展型数据能力 关键核心系统、成熟企业 IT 体系
默认事务引擎 / 内核 InnoDB 单一内核 单一内核
默认隔离级别 REPEATABLE READ READ COMMITTED READ COMMITTED
JSON 能力 JSON 类型与函数 json / jsonb,索引与操作符丰富 支持 JSON,企业版本特性随版本变化
地理空间 可用,但通常借助生态方案 PostGIS 是强项 有 Spatial 等企业能力
全文检索 FULLTEXT 内建全文检索、扩展丰富 Oracle Text 等产品能力
常用高可用形态 主从复制、MGR、InnoDB Cluster 流复制、逻辑复制、Patroni 等 Data Guard、RAC 等
典型学习 / 运维门槛 较低 中等 较高

表格用于建立方向感,不用于替代压测。比如“高并发”并不是 MySQL 的专属标签;一张缺少索引的表、一个长事务或错误的分页 SQL,换成任何数据库都会慢。

三、架构概念:同叫“数据库”,层级不完全一样

3.1 MySQL:一个实例下有多个 database

MySQL 常见的使用方式最直观:连接到一个 MySQL 实例,再通过 USE app_db; 进入某个数据库。表名通常写作 app_db.users。

1
2
3
4
5
6
CREATE DATABASE app_db;
USE app_db;
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL
);

MySQL 中的 database 和 schema 基本可以看成同义词。业务应用经常“一套服务一个库”,不同库之间通过账号权限隔离。

3.2 PostgreSQL:实例、database、schema 三层都要分清

PG 的一个实例可以创建多个 database;每个 database 内还可以建立多个 schema。默认 schema 是 public,对象的完整名字可以是 public.users。

1
2
3
4
5
6
7
CREATE DATABASE app_db;
-- 重新连接到 app_db 后执行
CREATE SCHEMA billing;
CREATE TABLE billing.invoices (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
amount NUMERIC(12, 2) NOT NULL
);

这意味着 PG 的 schema 很适合做同一数据库内的逻辑分区:例如 billing、identity、audit。它不是 MySQL 里“必须新建一个库”才能获得的唯一隔离方式。

3.3 Oracle:用户通常就是 schema

Oracle 的日常开发中,用户与 schema 紧密绑定:frank 用户创建的 users 表属于 frank.users。它没有 MySQL 那种通过 USE 切换当前库的工作流。

1
2
3
4
5
6
7
8
9
10
CREATE USER app_user IDENTIFIED BY "StrongPassword_123"
DEFAULT TABLESPACE users
QUOTA UNLIMITED ON users;
GRANT CREATE SESSION, CREATE TABLE TO app_user;

-- 重新以 app_user 登录后执行
CREATE TABLE users (
id NUMBER(19) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
username VARCHAR2(50 CHAR) NOT NULL
);

这里还会遇到 Oracle 的 CDB / PDB、表空间等概念。刚开始做业务表时无需死记全部存储层级,但要知道:**表逻辑上属于 schema,物理上存放在表空间的数据文件中。**更多入门操作可以读 Oracle 快速入门:15 分钟从安装到增删改查。

四、事务与并发:三者都有 MVCC,别只背概念

MVCC(多版本并发控制)的目标,是让读操作在多数情况下不必阻塞写操作。三者都有这类思想,但版本保存方式、垃圾清理和默认隔离级别不一样。

图2:三种数据库的 MVCC 与默认隔离级别速览

4.1 默认隔离级别会改变“同一段 SQL”的观察结果

  • MySQL InnoDB 默认 REPEATABLE READ:同一个显式事务里的普通快照读,通常会看到同一份一致性视图。针对范围条件的当前读,InnoDB 还可能使用 next-key lock,以降低幻读问题。
  • PostgreSQL 默认 READ COMMITTED:每条 SQL 语句在开始时看到一个新快照。因此同一个事务中先后执行两条 SELECT,第二条可能看见别的事务刚提交的数据。
  • Oracle 默认 READ COMMITTED:同样以语句级一致性读为常见行为;它通过 Undo 信息构造查询所需的历史版本。

下面两段查询都在观察“另一事务已提交更新后,第二次读取是否变化”这一问题,但事务控制语法要分开写:

1
2
3
4
5
6
7
8
9
10
11
-- MySQL / PostgreSQL:显式事务
BEGIN;
SELECT balance FROM accounts WHERE id = 1;
-- 这里另一个事务修改并提交了 id=1
SELECT balance FROM accounts WHERE id = 1;
COMMIT;

-- Oracle:SELECT 本身不显式开启事务;两条查询仍分别获取一致性视图
SELECT balance FROM accounts WHERE id = 1;
-- 这里另一个事务修改并提交了 id=1
SELECT balance FROM accounts WHERE id = 1;

在 MySQL 默认的 InnoDB REPEATABLE READ 下,两个普通快照读通常保持一致;在 PG、Oracle 默认 READ COMMITTED 下,第二条语句可能读到新值。需要锁定当前记录并修改时,明确写出 SELECT ... FOR UPDATE,并让事务尽量短。

4.2 三个容易被忽略的运维点

  1. MySQL:长事务会让 Undo Log 不能及时清理,还会放大锁等待;范围更新前要确认索引,避免锁住远多于预期的记录。
  2. PostgreSQL:更新会创建新的行版本,旧版本需由 VACUUM 回收。长事务会阻碍清理,最终可能导致表膨胀,因此要监控 autovacuum 和最老事务。
  3. Oracle:Undo 表空间既服务回滚也服务一致性读。长查询与大量更新并存时,应关注 Undo 的容量和保留策略,避免历史版本不足。

这些不是“某数据库有缺陷”,而是 MVCC 为了减少读写互相等待所付出的存储和清理成本。

五、最常碰到的 SQL 方言对照

应用层若使用 MyBatis、JPA 或 jOOQ,仍然需要知道这些差异。ORM 能减少重复代码,不能抹掉分页、自增、日期函数和锁语义的差异。

5.1 自增主键

1
2
3
4
5
6
7
8
-- MySQL
id BIGINT PRIMARY KEY AUTO_INCREMENT

-- PostgreSQL:推荐 Identity;老项目可能看到 SERIAL / BIGSERIAL
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY

-- Oracle(12c+)
id NUMBER(19) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY

老版本 Oracle 常见的写法是 SEQUENCE + TRIGGER,不要看到它就误以为项目写错了;只是新版本已经可以直接使用 IDENTITY。

5.2 分页

1
2
3
4
5
6
7
8
-- MySQL
SELECT * FROM orders ORDER BY id DESC LIMIT 20 OFFSET 40;

-- PostgreSQL
SELECT * FROM orders ORDER BY id DESC LIMIT 20 OFFSET 40;

-- Oracle 12c+
SELECT * FROM orders ORDER BY id DESC OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY;

OFFSET 越大,数据库跳过的记录越多。列表翻到很后面时,三者都更建议改成游标 / Keyset 分页:记录上一页最后一条的有序字段,再继续向后查。

1
2
3
4
5
-- 三者都容易迁移的思路:取下一页,而不是跳过 N 行
SELECT * FROM orders
WHERE id < :last_id
ORDER BY id DESC
FETCH FIRST 20 ROWS ONLY;

注意:MySQL / PG 也支持 FETCH FIRST 的版本与兼容性要按实际数据库确认;要追求跨库稳定,分页 SQL 通常交给方言层生成。

5.3 空值、字符串拼接和当前时间

目的 MySQL PostgreSQL Oracle
判空替换 IFNULL(a, b) COALESCE(a, b) NVL(a, b) 或 COALESCE(a, b)
字符串拼接 CONCAT(a, b) a || b a || b
当前时间 NOW() CURRENT_TIMESTAMP / NOW() SYSDATE / SYSTIMESTAMP
日期格式化 DATE_FORMAT(t, fmt) TO_CHAR(t, fmt) TO_CHAR(t, fmt)

COALESCE 是标准 SQL,能用时更利于跨库迁移。还要特别留意:Oracle 将空字符串 '' 视为 NULL,而 MySQL、PG 不这么处理;表单字段迁移到 Oracle 时,这会影响唯一约束、判空条件和业务校验。

5.4 插入冲突时更新(Upsert)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- MySQL
INSERT INTO user_settings (user_id, theme) VALUES (1, 'dark')
ON DUPLICATE KEY UPDATE theme = VALUES(theme);

-- PostgreSQL
INSERT INTO user_settings (user_id, theme) VALUES (1, 'dark')
ON CONFLICT (user_id) DO UPDATE SET theme = EXCLUDED.theme;

-- Oracle:常用 MERGE
MERGE INTO user_settings t
USING (SELECT 1 AS user_id, 'dark' AS theme FROM dual) s
ON (t.user_id = s.user_id)
WHEN MATCHED THEN UPDATE SET t.theme = s.theme
WHEN NOT MATCHED THEN INSERT (user_id, theme) VALUES (s.user_id, s.theme);

MySQL 8.0.20+ 对 VALUES(col) 在 ON DUPLICATE KEY UPDATE 中有弃用提示,生产项目可改用插入行别名;而不同数据库的冲突条件、并发细节也不相同。不要把 Upsert 当成“天然幂等”,仍需为业务唯一键设计正确的唯一约束。

5.5 标识符与 DDL 事务

  • 标识符大小写:PG 和 Oracle 未加双引号的标识符会分别折叠为小写、大写;一旦加双引号,就必须以后完全匹配大小写。团队最稳妥的约定是:表名、字段名统一小写下划线,不要随意加双引号。
  • DDL 能否回滚:PG 的大量 DDL 可以放在事务内回滚;MySQL 许多 DDL 会隐式提交;Oracle 的 DDL 会隐式提交当前事务。上线迁移脚本不能只凭“开发环境执行成功”判断可回滚性。

六、数据类型与扩展:PG 经常在这一项胜出

6.1 JSON:不是存进去就结束

三者都能存 JSON,但表达力不同:

  • MySQL 的 JSON 适合在关系表中保存少量变化快的扩展属性,并配合生成列或函数索引优化热点字段。
  • PG 的 jsonb 会以二进制形式处理,配合 GIN 索引和丰富操作符,特别适合需要按 JSON 内部结构检索的场景。
  • Oracle 也支持 JSON 相关类型与函数,但具体能力与许可证要按数据库版本、部署形态核对。

无论选谁,关键条件仍要优先建成普通列并建立合适索引。把所有字段都塞进 JSON,只会把关系型数据库变成难维护的“半文档库”。

6.2 复杂数据能力

PG 常被选中的原因还包括:ARRAY、范围类型、枚举、窗口函数、CTE、物化视图,以及 PostGIS。它们让某些本该拆到多个中间服务或额外产品的需求,可以先在一个数据库中可靠完成。

MySQL 与 Oracle 也有各自的空间、全文检索、分析函数和分区能力。区别不在于“能不能写”,而在于项目是否需要这类能力作为主要竞争力,以及团队是否能把它们长期运维好。

七、实际项目到底怎么选?

先判断不可谈判的硬约束,再看最核心的负载和团队能力,而不是先挑一个数据库再为它找理由。

图3:数据库选型先排除硬约束,再按核心负载与团队能力收敛

优先选 MySQL 的情况

  • 新建的后台、内容、电商、订单、SaaS 等常规 Web 业务;
  • 团队现有监控、备份、分库分表、读写分离体系围绕 MySQL;
  • 当前核心是稳定完成 OLTP,而不是复杂数据计算;
  • 需要快速招聘、交接,或希望从大量社区经验中直接受益。

建议阅读 MySQL 从零到一(01):数据库与 SQL 基础,再继续学习事务、索引和慢 SQL。数据库性能的第一生产力始终是正确的模型和索引,而非换产品。

优先评估 PostgreSQL 的情况

  • 业务依赖复杂查询、窗口分析、CTE、全文搜索,或需要丰富的可扩展类型;
  • 有明确的地理空间需求,计划使用 PostGIS;
  • JSON 内部查询很多,且不想为每项检索再同步一套搜索系统;
  • 团队愿意掌握执行计划、索引类型、VACUUM 和复制等 PG 运维要点。

“PG 功能更多”并不自动代表应当选 PG。若团队完全没有经验、需求又只是用户表和订单表,MySQL 往往是更经济的起点。

继续使用或选用 Oracle 的情况

  • 客户、行业规范或现有核心系统已经明确要求 Oracle;
  • 对审计、权限、高可用、容灾和商业支持有严格采购与合规要求;
  • 团队已有 DBA、备份恢复流程和成熟的 Oracle 运维体系;
  • 迁移成本和兼容性风险远高于许可成本。

新项目如果只是因为“Oracle 更专业”而引入它,先把许可、版本、容器/云部署限制、备份演练和 DBA 能力写入项目预算。技术选型需要计算全生命周期成本。

八、那 SQL Server、SQLite、MariaDB 呢?

本文重点比较最常见的三种,但实际工作还会遇到:

数据库 更适合什么场景 一句话提醒
SQL Server .NET / Microsoft 技术栈、企业 BI 与 Windows 生态 工具链和企业集成强,Linux 与容器支持也已成熟
SQLite 移动端、桌面端、嵌入式、单机工具、测试 它是文件级数据库,不是替代高并发服务端数据库的方案
MariaDB 希望保留 MySQL 使用体验与开源路线的团队 与 MySQL 不是永久“完全兼容”,版本功能要逐项核对
Redis / Elasticsearch 缓存、排行榜、搜索等特定能力 多数情况下是关系型数据库的补充,不是直接替换

九、上线前的选型自查清单

在技术评审会上,把下面问题写成答案,而不是只写一个数据库名字:

  1. 客户、已有系统、云产品或合规条款是否已经指定数据库?
  2. 未来一年最主要的读写模型是什么:点查、事务写入、复杂报表、全文搜索还是地理查询?
  3. 需要哪些高可用指标:RPO、RTO、异地容灾、演练频率?
  4. 团队是否真的能做备份恢复演练、慢 SQL 分析、复制故障切换?
  5. 数据量增长后,分区、归档、冷热分离的路径是什么?
  6. 应用框架、驱动、迁移工具、BI 工具是否都兼容目标版本?
  7. 许可、云实例、商业支持和人力成本,三年合计是多少?
  8. 如果未来要迁移,SQL 方言、数据类型和存储过程会把你锁定到什么程度?

十、总结

  • MySQL:常规 Web OLTP 的可靠默认选项,生态和人才最普及。
  • PostgreSQL:当复杂 SQL、丰富类型、JSONB、GIS 或扩展能力是真实需求时,值得优先评估。
  • Oracle:适合已有 Oracle 生态及对企业治理、关键业务连续性要求极高的场景,但要接受更高的许可和运维投入。
  • 三者都有事务、索引、MVCC 和高可用方案;真正决定稳定性的,往往是模型、索引、事务边界、备份演练和团队经验。
  • 选型不是数据库能力排行,而是硬约束、主负载、团队能力和总成本的平衡。
上一页
2026-10-12 09:40:00
下一页