MySQL 核心架构速览

理解 MySQL 的工作原理是所有优化的前提。


这个问题触及了 MySQL 的核心——InnoDB 存储引擎。在 InnoDB 中,数据不是杂乱无章丢进文件的,而是有着极其严密的层级结构。

简单来说,数据存储的层级是:表空间 -> 段 -> 区 -> 页 -> 行


最小存储单位:页(Page)

在讨论“行”之前,必须先理解“页”。

$$\text{页大小 (16KB)} \ge (\text{阶数 } M - 1) \times \text{索引键大小} + M \times \text{指针大小} + \text{页头元数据}$$

一般而言,表在创建的时候B+数的阶是确定的(根据索引大小和页大小确定)


行格式(Row Format)

MySQL 提供了几种行格式(如 Compact, Redundant, Dynamic, Compressed)。目前最常用的是 Dynamic(MySQL 5.7 后的默认格式)。

一行的存储结构主要分为两个部分:记录的额外信息记录的真实数据

A. 记录的额外信息(Metadata)

这部分是为了让数据库引擎能“读懂”这一行:

  1. 变长字段长度列表:记录像 VARCHARTEXT 这种变长字段实际占用了多少字节。
  2. NULL 值列表:用位图(Bit Map)记录哪些列是 NULL,这样就不需要为 NULL 值浪费实际存储空间。
  3. 记录头信息:包含一些标志位(比如该行是否被删除、下一条记录的相对位置指针等)。

B. 记录的真实数据(Real Data)

除了你定义的字段(如 name, age)外,InnoDB 还会自动加上三个隐式列


溢出列(Off-page Column)

如果一个字段特别大(比如 VARCHAR(65535)BLOB),一个 16KB 的页根本装不下怎么办?


行在页中是如何排列的?

在页内部,行记录是按主键顺序排列成一个单向链表的。

为了提高查询效率,页内还有一个 页目录(Page Directory)。它将行记录分成几个小组(Slot),通过二分法快速定位到具体的行,避免了从头到尾遍历链表的低效。


为什么一行不能超过 8KB?

虽然一个页有 16KB,但 MySQL 规定一个页至少要存 2 行数据(为了保证 B+ 树的层级结构稳定)。

加上页头、页尾的开销,如果你定义的所有列加起来超过了约 8KB,MySQL 就会强制将变长字段转移到溢出页中。


总结

当你插入一行数据时,MySQL 实际上是在:

  1. 计算变长字段长度和 NULL 值情况。
  2. 加上事务 ID 和回滚指针。
  3. 将其塞进 B+ 树叶子节点的某个 16KB 的页里。
  4. 如果太大了,就“分家”存到溢出页。

你想了解一下当这一行数据被删除时,它在磁盘上是立即消失了,还是只是被标记了一下?(这涉及到了数据页的碎片处理)

索引(重点中的重点)

索引是面试中出现率最高的话题。


事务与并发控制

一致性核心定义:从一个合法状态到另一个合法状态。 一致性指事务执行前后,数据库必须处于合法状态,即满足所有完整性约束与业务不变量。

什么是“合法”状态:

  • 数据库完整性约束:主键唯一、NOT NULL、外键引用有效、数值范围限制(例如余额不能为负)等。
  • 业务实体完整性(业务不变量):由应用定义的规则。例如:在转账操作中,A 向 B 转账 100 元时,A 的余额需减少 100、B 的余额需增加 100,总金额保持不变。

如果事务执行完,导致数据库违反了上述任何一条规则,那这个事务就打破了一致性,数据库必须将其回滚。

  1. 读未提交 (Read Uncommitted)
  2. 读已提交 (Read Committed)
  3. 可重复读 (Repeatable Read) —— MySQL 默认级别,通过 MVCC 部分解决幻读。
  4. 串行化 (Serializable)

解释脏读、不可重复读、幻读

快照读:

当前读: 通过行锁/GAP锁

注意:Snapshot Isolation(MVCC 的快照机制)并不完全等价于 SERIALIZABLE。在可重复读下,仍然可能发生逻辑异常,特别是在涉及多行或跨表约束的场景中。

Write Skew(写倾斜)简述

RR 的三大弱点

除了写倾斜之外,RR 级别还有几个容易踩到的陷阱:

实效防护策略


高频问题

题目考察点核心回答关键词
MySQL 为什么选 B+ 树?数据结构磁盘 IO 效率、范围查询、叶子节点双向链表。
什么是慢查询?如何优化?实战能力EXPLAIN 分析、索引失效排查、深分页优化。
binlog, redolog, undolog 区别?日志系统崩溃恢复 (redo)、数据备份 (bin)、事务回滚 (undo)。
InnoDB 如何解决幻读?锁机制Next-Key Locks (行锁 + 间隙锁) + MVCC。
主从复制的原理是什么?高可用binlog、dump thread、relay log (中继日志)。

避坑指南(进阶建议)

  1. 别在索引列上做运算SELECT * FROM t WHERE id + 1 = 10; 会导致全表扫描。
  2. 小心 SELECT *:这通常是性能杀手,且无法利用覆盖索引。
  3. 深度分页LIMIT 1000000, 10 会扫描前一百万行,建议通过子查询或标签 ID 优化。

事务与锁

两阶段锁协议(2PL)

InnoDB 的行锁实现基于两阶段锁协议:

这种协议保证了可串行化执行,避免了常见的并发异常。

MVCC 与快照读

InnoDB 使用多版本并发控制(MVCC)来实现高并发读取:

但 MVCC 并不能直接防止所有幻读,InnoDB 结合锁机制来实现更强的隔离。

锁的粒度与类型

InnoDB 支持多种锁:

读写锁(共享锁 / 排他锁)

InnoDB 的锁分为两类:

常见场景:

事务隔离与锁策略

MySQL 默认隔离级别是 REPEATABLE READ

当需要更强隔离时,可以使用:

事务提交与锁释放

进阶提示