数据库系列(一):从一行 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 篇
8MVCC 与隔离级别第 5 篇
7锁与并发控制第 6 篇
5,9日志与崩溃恢复第 7 篇
10复制与高可用第 8 篇
2,3SQL 方言与查询优化器第 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 横向对比表

维度OracleSQL ServerMySQLPostgreSQL
进程/线程多进程多线程(SQLOS)多线程多进程
共享内存SGABuffer Pool(用户态)Buffer Pool(用户态)Shared Buffers
连接模型Dedicated/SharedThread poolThread-per-connProcess-per-conn
后台任务DBWn/LGWR/SMON后台线程Master/Purge/Cleanerbgwriter/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 + RBORow-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 怎么保证?分布式事务怎么落?
5MVCC 与隔离级别为什么读不阻塞写?为什么 PostgreSQL 表会膨胀?
6锁与并发控制行锁怎么实现?SQL Server 为什么会锁升级?死锁怎么破?
7日志与崩溃恢复Redo、Undo、Binlog、WAL 这么多日志都是干嘛的?
8复制与高可用主从怎么同步?脑裂怎么防?RAC、MGR、AlwaysON 各是什么?
9SQL 方言与优化器同样的 SQL 为什么在 PG 比 MySQL 快 10 倍?
10数据存储全景OLTP、OLAP、HTAP、数仓、Lakehouse 怎么选?

每篇都会包含三个层次:

  • 原理:核心机制 + 算法 + 数据结构
  • 对比:四家差异 + 命名对照 + 优劣
  • 实战:执行计划、配置参数、踩坑案例

六、核心术语对照表

四大数据库的术语往往表达同一个概念,但叫法完全不同。这张表是后续阅读的"翻译字典"。

6.1 内存相关

概念OracleSQL ServerMySQL (InnoDB)PostgreSQL
数据缓存Buffer CacheBuffer PoolBuffer PoolShared Buffers
日志缓存Redo Log BufferLog CacheRedo Log BufferWAL Buffers
共享内存区SGA——(用户态分配)——(用户态分配)Shared Memory
私有内存PGA——Thread stackProcess Mem
SQL/计划缓存Shared Pool (Library Cache)Plan CacheQuery Cache(已废弃)plpgsql cache

6.2 后台任务

任务OracleSQL ServerMySQLPostgreSQL
写脏页DBWnCheckpoint/Lazy WriterPage Cleanerbgwriter / checkpointer
写日志LGWRLog WriterLog Managerwalwriter
清理旧版本SMON(Undo 表空间)——(tempdb 清理)Purge Threadautovacuum
统计信息收集自动(GATHER_STATS_JOB)自动自动(默认开启)autovacuum 分析

6.3 日志类型

用途OracleSQL ServerMySQLPostgreSQL
Redo(重做)Redo LogTransaction LogRedo Log(ib_logfile)WAL
Undo(回滚)Undo 表空间Transaction Log(同一份)Undo Log(undo tablespace)Old tuple in heap
归档Archive Log——(备份 log backup)BinlogWAL archive
主从复制Redo + ArchiveTransaction LogBinlogWAL 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 索引术语

概念OracleSQL ServerMySQL (InnoDB)PostgreSQL
主键索引IOT / 普通索引Clustered IndexClustered Index(=数据)普通索引(堆表)
二级索引Normal IndexNonclustered IndexSecondary IndexIndex
唯一索引Unique IndexUnique IndexUnique IndexUnique Index
联合索引CompositeCompositeCompositeComposite
函数索引Function-basedComputed ColumnFunctional(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 的主键就是数据本身。