MySQL 存储原理相关问题¶
一、InnoDB vs MyISAM¶
| InnoDB | MyISAM | |
|---|---|---|
| 事务 | ✅ | ❌ |
| 外键 | ✅ | ❌ |
| 锁粒度 | 行锁 | 表锁 |
| MVCC | ✅ | ❌ |
| 主键 | 聚簇索引 | 非聚簇 |
| 崩溃恢复 | ✅(redo log) | ❌ |
MySQL 5.5 之后默认 InnoDB。
二、聚簇索引与非聚簇索引¶
聚簇索引(Clustered Index)¶
InnoDB 的主键索引就是聚簇索引,叶子节点直接存整行数据。一张表只有一个聚簇索引。
如果没定义主键,InnoDB 会: 1. 选第一个非空唯一索引。 2. 都没有,自动生成一个 6 字节的隐藏主键。
非聚簇索引(Secondary Index / 二级索引)¶
叶子节点存主键值,不是行地址。
通过二级索引查完整行:
- 在二级索引找到主键值。
- 回到聚簇索引取整行(回表)。
如果二级索引已经包含要查的列(覆盖索引),就不用回表。
三、B+ 树为什么适合做索引¶
与二叉树、B 树、Hash 对比:
| 结构 | 特点 |
|---|---|
| 二叉树 | 树太高,IO 次数多 |
| B 树 | 非叶子节点也存数据,单节点能放的 key 少 |
| B+ 树 | 非叶子节点只存 key,单节点放更多 key,树更矮;叶子节点链表相连,范围查询快 |
| Hash | 等值查询 O(1),但不支持范围、排序 |
InnoDB 的 B+ 树通常 3~4 层就能支撑千万级数据,查询一次最多 3~4 次磁盘 IO。
四、页(Page)¶
InnoDB 最小存储单位是 页,默认 16KB。一个页内有多条记录,按主键有序排列。
- 查询时按页加载到 Buffer Pool。
- 页内用二分查找。
- 页之间用双向链表。
五、Redo Log 与 Undo Log¶
Redo Log(重做日志)¶
- 保证事务持久性(Durability)。
- WAL(Write-Ahead Logging):先写 redo log,再写数据页。
- crash-safe:宕机后用 redo log 重放。
Undo Log(回滚日志)¶
- 保证原子性(Atomicity)。
- 记录修改前的旧值,用于回滚和 MVCC。
Binlog(归档日志)¶
- Server 层日志,记录所有变更。
- 主从复制、数据恢复用。
高频追问
- 为什么 InnoDB 推荐自增主键?B+ 树按主键顺序插入,避免页分裂;UUID 主键是无序的,导致页分裂频繁。
- 什么是页分裂?插入新记录时页满了,申请新页,把一半数据移过去。