写在前面
本文是数据库系列的第一篇。这个系列计划写 10 篇,主线是横向对比 Oracle、SQL Server、MySQL、PostgreSQL 四大关系数据库的底层原理,并在最后跳出来俯瞰整个数据存储生态(OLAP / 数仓 / Lakehouse)。
开篇不深入任何单一原理,目标是建立一张"原理地图"——用一行 UPDATE 语句把整本系列的 10 个主题串起来,让你看后面每一篇时都知道它处在地图的哪一格。
一、从一行 UPDATE 说起
考虑这条最普通的 SQL:
1
| UPDATE accounts SET balance = balance - 100 WHERE id = 42;
|
在你按下回车到返回"1 row affected"之间,数据库内部发生的事情远比你想象的多:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 1. 连接层: 校验会话、权限、参数绑定
2. 解析器: 词法/语法分析,生成 AST
3. 优化器: 决定走哪个索引、用什么 JOIN 顺序
4. 执行器: 按"打开表 → 定位行 → 改字段"的步骤执行
5. 事务层: 写 Undo Log(保证可回滚)+ 写 Redo Log(保证持久)
6. 缓冲池: 修改的是内存中的页,并不立即落盘
7. 锁系统: 对 id=42 这行加 X 锁,避免其他事务改
8. MVCC: 旧版本写入 Undo 链,让并发读不会看到新值
9. 提交: Redo Log fsync 到磁盘,事务正式可见
10. 复制: Redo/WAL 流式推送给从库(如果是主从架构)
后续:
- 后台 Checkpoint 把脏页刷盘
- 崩溃重启时用 Redo 重放、Undo 回滚
- Binlog 也会被消费同步到下游(订阅 / 数仓)
|
这一行 SQL 牵出了 10 个原理子系统,正是本系列要逐个深挖的:
| 步骤 | 涉及子系统 | 本系列对应篇 |
|---|
| 4-5 | 存储引擎(数据怎么放、页怎么组织) | 第 2 篇 |
| 3,4 | 索引(怎么定位 id=42 这行) | 第 3 篇 |
| 5,9 | 事务 ACID(原子性 + 持久性) | 第 4 篇 |
| 8 | MVCC 与隔离级别 | 第 5 篇 |
| 7 | 锁与并发控制 | 第 6 篇 |
| 5,9 | 日志与崩溃恢复 | 第 7 篇 |
| 10 | 复制与高可用 | 第 8 篇 |
| 2,3 | SQL 方言与查询优化器 | 第 9 篇 |
| —— | 数据存储全景(OLAP/数仓/Lakehouse) | 第 10 篇 |
读完这 10 篇,再回头看这行 UPDATE,你应当能说清每一步在四大数据库里叫什么名字、走什么代码路径、踩到哪些坑。
二、四大关系数据库的身世
2.1 Oracle:商业数据库的标杆
1
2
3
4
5
| 出身:1979 年由 Larry Ellison 创立,关系数据库商业化的先驱
版本:Oracle 7 → 8i → 9i → 10g → 11g → 12c → 18c → 19c → 21c → 23ai
定位:企业级核心交易系统、大型 OLTP、数据仓库
关键词:SGA/PGA、RAC(共享存储集群)、Data Guard、ASM、Exadata 一体机
许可证:商业,按 CPU 插槽计费,昂贵
|
2.2 SQL Server:微软生态的深度集成
1
2
3
4
5
| 出身:1989 年微软与 Sybase 合作开发,后独立分叉
版本:6.5 → 7.0 → 2000 → 2005 → ... → 2019 → 2022
定位:Windows 生态首选、企业 OLTP、近年也做 Linux + 容器
关键词:T-SQL、SQLOS、AlwaysOn、MSDTC、Columnstore、SSIS/SSAS/SSRS
许可证:商业,按 Core 计费,Express 免费但有限制
|
2.3 MySQL:互联网公司的最爱
1
2
3
4
5
6
| 出身:1995 年瑞典 MySQL AB 公司,2008 被 Sun 收购,2010 被 Oracle 收购
版本:3.x → 4.x → 5.x → 8.0 → 8.4 → 9.x(创新版)
分支:MariaDB(MySQL 创始人 fork)、Percona Server(性能版)
定位:互联网 OLTP、Web 应用、电商
关键词:InnoDB(默认引擎)、Binlog、MGR(Group Replication)、半同步复制
许可证:GPL + 商业双授权
|
2.4 PostgreSQL:最像 Oracle 的开源数据库
1
2
3
4
5
| 出身:1996 年从 Berkeley 的 POSTGRES 项目演化而来,2010 后社区爆发
版本:9.x → 10 → 11 → ... → 17
定位:复杂查询、地理数据(PostGIS)、JSON、扩展生态
关键词:进程模型、WAL、流复制 + 逻辑复制、丰富的索引类型、扩展(Extension)
许可证:PostgreSQL License(BSD-like),完全开源
|
2.5 四家定位坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| OLAP 能力 ↑
│
Oracle ───────┼──────── PostgreSQL
│
SQL Server │
│
──────────────────┼────────────── 成熟度 →
│
MySQL │
│
OLTP 能力 ↑(其实是同一轴)
不同象限的擅长领域:
- Oracle/SQL Server:金融核心、ERP、关键交易系统
- MySQL:互联网高并发 OLTP
- PostgreSQL:复杂分析、地理数据、JSON 存储
|
三、进程/线程模型对比
四大数据库的"骨架"——也就是它们如何组织进程/线程——差异巨大。这个差异决定了内存架构、连接方式、并发性能的根本走向。
3.1 Oracle:多进程 + 共享内存(SGA)
1
2
3
4
5
6
7
8
9
10
11
12
| 一个 Oracle 实例由多个进程组成,进程间通过共享内存段(SGA)通信:
┌──────────────────────────────────────┐
│ SGA(共享内存) │
│ Buffer Cache / Redo Buffer / │
│ Shared Pool / Large Pool / Java Pool│
└────┬──────┬──────┬──────┬──────┬─────┘
│ │ │ │ │
PMON SMON DBWn LGWR CKPT ...(后台进程)
▲
│
Server Process(每个会话一个,或共享)
|
1
2
3
4
5
6
| 特点:
- 后台进程分工:DBWn 写脏页、LGWR 写 Redo、SMON 系统监控、PMON 进程监控
- 两种连接模式:
* Dedicated Server:每个会话一个 server 进程(默认)
* Shared Server:通过 dispatcher 共享,适合大量短连接
- 进程间通过共享内存(SGA)高效通信,无 IPC 开销
|
3.2 SQL Server:单进程多线程(SQLOS)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| SQL Server 是一个进程,里面跑数千个线程,由 SQLOS(调度器)管理:
┌──────────────────────────────────────┐
│ sqlservr.exe(单进程) │
│ ┌─────────────────────────────┐ │
│ │ SQLOS │ │
│ │ Scheduler(每 CPU 一个) │ │
│ └────────┬────────┬────────┬───┘ │
│ │ │ │ │
│ Worker Worker Worker │
│ (线程) (线程) (线程) │
└──────────────────────────────────────┘
│
Buffer Pool(用户态内存)
|
1
2
3
4
5
6
| 特点:
- 单进程多线程,所有连接共用一个进程
- SQLOS:自研的用户态调度器,避免 OS 上下文切换
- 每个 CPU 一个 Scheduler,Worker 跑在上面
- 内存:Buffer Pool 是用户态分配,不需要共享内存段
- 线程切换比进程切换便宜,适合极高并发
|
3.3 MySQL:多线程(每个连接一个线程)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| MySQL 服务器进程是单进程多线程,类似 SQL Server:
┌──────────────────────────────────────┐
│ mysqld(单进程) │
│ ┌────────────────────┐ │
│ │ Server Layer │ │
│ │ (解析/优化/执行) │ │
│ └─────────┬──────────┘ │
│ │ │
│ ┌─────┴───────┐ │
│ ▼ ▼ │
│ InnoDB 其他引擎 │
│ (独立线程池) │
└──────────────────────────────────────┘
线程类型:
- connection thread:每个客户端连接一个
- innodb master thread:刷盘、合并
- purge thread:清理 Undo
- page cleaner thread:刷脏页
- IO thread:AIO 读写
|
1
2
3
4
5
| 特点:
- Server Layer + Storage Engine 双层架构(引擎可插拔)
- 默认每个连接一个线程(thread-per-connection)
- 5.5+ 支持 thread pool(企业版 / Percona / MariaDB)
- InnoDB 内部有独立的线程池负责后台任务
|
3.4 PostgreSQL:多进程(每个连接一个进程)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| PostgreSQL 是最传统的"多进程"架构:
┌──────────────────────────────────────┐
│ postmaster(主进程) │
│ fork │
│ ├── backend(连接 1) │
│ ├── backend(连接 2) │
│ └── backend(连接 3) │
│ │
│ + 后台进程: │
│ checkpointer、bgwriter、walwriter │
│ autovacuum、stats collector │
└──────────────────────────────────────┘
│
Shared Buffers(共享内存段,System V / POSIX shm)
|
1
2
3
4
5
6
7
| 特点:
- 每个连接 fork 一个 backend 进程(进程模型)
- 进程间通过共享内存通信(Shared Buffers)
- 类似 Oracle,但更"原始":没有 dispatcher 模式
- 优点:进程隔离好,崩溃不影响其他连接
- 缺点:进程比线程重,大量连接时内存开销大
- 连接池方案:pgbouncer / pgcat(在客户端和数据库之间)
|
3.5 横向对比表
| 维度 | Oracle | SQL Server | MySQL | PostgreSQL |
|---|
| 进程/线程 | 多进程 | 多线程(SQLOS) | 多线程 | 多进程 |
| 共享内存 | SGA | Buffer Pool(用户态) | Buffer Pool(用户态) | Shared Buffers |
| 连接模型 | Dedicated/Shared | Thread pool | Thread-per-conn | Process-per-conn |
| 后台任务 | DBWn/LGWR/SMON | 后台线程 | Master/Purge/Cleaner | bgwriter/walwriter |
| 大量连接方案 | Shared Server | 默认就支持 | 企业版线程池 | pgbouncer |
1
2
3
4
| 关键差异:
- Oracle/PG:操作系统级进程,崩溃影响小但开销大
- MSSQL/MySQL:用户态线程,开销小但单线程 bug 会拖垮整个实例
- PG 是四家里连接模型最"重"的,所以 pgbouncer 几乎是生产标配
|
四、整体架构
抛开进程/线程细节,关系数据库的逻辑架构大体是相似的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| ┌──────────────────────────────────────┐
│ 客户端 / Driver │
└─────────────────┬────────────────────┘
│ SQL(TDS/MySQL/Wire/Net8 协议)
▼
┌──────────────────────────────────────┐
│ 连接层 │
│ 鉴权 / 会话 / 进程或线程分配 │
└─────────────────┬────────────────────┘
▼
┌──────────────────────────────────────┐
│ 解析器 Parser │
│ SQL 文本 → AST 语法树 │
└─────────────────┬────────────────────┘
▼
┌──────────────────────────────────────┐
│ 优化器 Optimizer │
│ AST → 执行计划(RBO / CBO) │
└─────────────────┬────────────────────┘
▼
┌──────────────────────────────────────┐
│ 执行器 Executor │
│ 算子:Scan/Filter/Join/Agg/Sort │
└─────────────────┬────────────────────┘
▼
┌──────────────────────────────────────┐
│ 存储引擎 Storage Engine │
│ 页/块读写、缓冲池、索引、事务、日志 │
└─────────────────┬────────────────────┘
▼
磁盘 / SSD
|
4.1 MySQL 的特殊之处:可插拔存储引擎
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| Server Layer(解析/优化/执行)和 Storage Engine 是分离的:
Server Layer
├── InnoDB ← 默认,事务、行锁、MVCC
├── MyISAM ← 老引擎,表锁,已不推荐
├── Memory ← 内存表
├── Archive ← 压缩归档
├── NDB ← 集群(MySQL Cluster)
└── 第三方:RocksDB、TokuDB、TiDB(兼容协议)
其他三家:
- Oracle:可换段类型(heap / index-organized / partitioned),但引擎统一
- SQL Server:可换页压缩、列存索引,但引擎统一
- PostgreSQL:12+ 有 Table Access Method 抽象,目前主要是 heap
|
MySQL 这种设计的好处和代价:
- 好处:可以针对场景选引擎(OLTP 用 InnoDB,归档用 Archive)
- 代价:跨引擎功能不统一(MyISAM 不支持事务、InnoDB 才有外键等)
4.2 解析器与优化器
| 数据库 | 解析器 | 优化器 | 执行器 |
|---|
| Oracle | 自研 | CBO + RBO | Row-based + Vectorized(12c+) |
| SQL Server | 自研 | CBO(Cost-Based) | Row + Batch mode |
| MySQL | 自研(8.0+ 重大重写) | CBO(5.7+ 完善) | Iterator + Volcano |
| PostgreSQL | 自研(基于 flex/bison) | CBO + Genetic(GEQO) | Volcano model |
后续第 9 篇会深入展开优化器对比,这里先建立"解析器 → 优化器 → 执行器"的概念骨架。
五、本系列 10 篇要解决的 10 个问题
把 10 篇的目标用一句话讲清楚:
| 篇 | 主题 | 一句话问题 |
|---|
| 1(本篇) | 开篇总览 | 关系数据库内部到底有几个子系统? |
| 2 | 存储引擎 | 一行数据在磁盘上长什么样?为什么 MySQL 主键就是数据? |
| 3 | 索引原理 | 为什么几乎所有索引都是 B+ 树?PG 的 GIN/GiST 又是什么? |
| 4 | 事务 ACID | 原子性怎么实现?Durability 怎么保证?分布式事务怎么落? |
| 5 | MVCC 与隔离级别 | 为什么读不阻塞写?为什么 PostgreSQL 表会膨胀? |
| 6 | 锁与并发控制 | 行锁怎么实现?SQL Server 为什么会锁升级?死锁怎么破? |
| 7 | 日志与崩溃恢复 | Redo、Undo、Binlog、WAL 这么多日志都是干嘛的? |
| 8 | 复制与高可用 | 主从怎么同步?脑裂怎么防?RAC、MGR、AlwaysON 各是什么? |
| 9 | SQL 方言与优化器 | 同样的 SQL 为什么在 PG 比 MySQL 快 10 倍? |
| 10 | 数据存储全景 | OLTP、OLAP、HTAP、数仓、Lakehouse 怎么选? |
每篇都会包含三个层次:
- 原理:核心机制 + 算法 + 数据结构
- 对比:四家差异 + 命名对照 + 优劣
- 实战:执行计划、配置参数、踩坑案例
六、核心术语对照表
四大数据库的术语往往表达同一个概念,但叫法完全不同。这张表是后续阅读的"翻译字典"。
6.1 内存相关
| 概念 | Oracle | SQL Server | MySQL (InnoDB) | PostgreSQL |
|---|
| 数据缓存 | Buffer Cache | Buffer Pool | Buffer Pool | Shared Buffers |
| 日志缓存 | Redo Log Buffer | Log Cache | Redo Log Buffer | WAL Buffers |
| 共享内存区 | SGA | ——(用户态分配) | ——(用户态分配) | Shared Memory |
| 私有内存 | PGA | —— | Thread stack | Process Mem |
| SQL/计划缓存 | Shared Pool (Library Cache) | Plan Cache | Query Cache(已废弃) | plpgsql cache |
6.2 后台任务
| 任务 | Oracle | SQL Server | MySQL | PostgreSQL |
|---|
| 写脏页 | DBWn | Checkpoint/Lazy Writer | Page Cleaner | bgwriter / checkpointer |
| 写日志 | LGWR | Log Writer | Log Manager | walwriter |
| 清理旧版本 | SMON(Undo 表空间) | ——(tempdb 清理) | Purge Thread | autovacuum |
| 统计信息收集 | 自动(GATHER_STATS_JOB) | 自动 | 自动(默认开启) | autovacuum 分析 |
6.3 日志类型
| 用途 | Oracle | SQL Server | MySQL | PostgreSQL |
|---|
| Redo(重做) | Redo Log | Transaction Log | Redo Log(ib_logfile) | WAL |
| Undo(回滚) | Undo 表空间 | Transaction Log(同一份) | Undo Log(undo tablespace) | Old tuple in heap |
| 归档 | Archive Log | ——(备份 log backup) | Binlog | WAL archive |
| 主从复制 | Redo + Archive | Transaction Log | Binlog | WAL stream |
1
2
3
4
5
| 关键观察:
- Oracle / PG 把 Redo 和 Undo 完全分离
- SQL Server 在同一个 Transaction Log 里同时承担 Redo/Undo
- MySQL InnoDB 同时有 Redo Log 和 Undo Log,再加上 Binlog
- 复制日志:MySQL 用 Binlog,其他三家直接用 Redo/WAL/Transaction Log
|
6.4 索引术语
| 概念 | Oracle | SQL Server | MySQL (InnoDB) | PostgreSQL |
|---|
| 主键索引 | IOT / 普通索引 | Clustered Index | Clustered Index(=数据) | 普通索引(堆表) |
| 二级索引 | Normal Index | Nonclustered Index | Secondary Index | Index |
| 唯一索引 | Unique Index | Unique Index | Unique Index | Unique Index |
| 联合索引 | Composite | Composite | Composite | Composite |
| 函数索引 | Function-based | Computed Column | Functional(5.7+) | Expression Index |
| 位图索引 | Bitmap | ——(仅 DW 用) | —— | —— |
| 倒排索引 | —— | —— | —— | GIN |
| 部分索引 | —— | Filtered | —— | Partial Index |
后续第 3 篇会展开。
七、选型哲学
讲完架构,最后聊点选型。每家数据库都有它最舒服的场景,没有"银弹"。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| Oracle 适合:
- 核心金融、ERP,对一致性要求极高
- 预算充足、需要商业支持
- 需要 RAC 共享存储集群(单库扩展到多节点)
SQL Server 适合:
- 已是 Windows + .NET 生态
- 需要 BI 全家桶(SSIS/SSAS/SSRS)
- 内部团队熟悉 T-SQL
- 也适合 Linux 部署(2017+)
MySQL 适合:
- 互联网高并发 OLTP
- 数据规模可控(单库 TB 级以内)
- 团队熟悉 LAMP/LEMP 栈
- 需要多种存储引擎灵活搭配
PostgreSQL 适合:
- 复杂查询、分析型负载
- 需要 JSON / JSONB / GIS(PostGIS)
- 希望使用 BSD-like 许可证
- 想用 Oracle 但预算不够(PG 的语法/特性最像 Oracle)
|
7.1 一些常见的误区
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 误区 1:MySQL 比 PostgreSQL 慢
真相:纯单条 OLTP 写入,InnoDB 通常更快;复杂分析查询 PG 更快。
误区 2:Oracle 一定比开源好
真相:除非用 RAC / Exadata / 高级安全特性,PG/MySQL 8.x 能覆盖大部分场景。
误区 3:PostgreSQL 不能做高并发
真相:配合 pgbouncer + 多实例,PG 也能撑住极高并发;只是默认配置不如 MySQL。
误区 4:SQL Server 只能跑 Windows
真相:2017+ 官方支持 Linux + Docker,但生态工具仍以 Windows 为主。
误区 5:四大数据库的功能都差不多
真相:底层架构差异巨大——进程模型、日志、MVCC、复制、锁——这些都影响生产实践。
|
八、小结
本文作为开篇,主要做了三件事:
- 用一行 UPDATE 串联起本系列要讲的 10 个原理子系统
- 横向对比了四大数据库的身世、进程模型、整体架构
- 给出四方言核心术语对照表(内存、后台、日志、索引)
1
2
3
4
| 记住三句话:
1. 四大数据库解决的是同一组问题,但答案不同
2. 进程/线程模型是其他所有差异的根源
3. 同一个概念在四家里叫不同名字,建立"翻译字典"是基本功
|
下一篇将从"数据在磁盘上长什么样"开始,深入存储引擎的世界:页、块、Extent、Segment、堆表 vs 索引组织表,以及为什么 MySQL 的主键就是数据本身。