数据库系列(一):从一行 UPDATE 看懂关系数据库

写在前面

本文是数据库系列的第一篇。这个系列计划写 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 的主键就是数据本身。