一、前言
对以往接触到的 MYSQL 相关技术及面试中有可能遇到的问题进行汇总整理(不定期更新),方便未来查阅复习。
二、MySQL 简介
MySQL 是目前世界上最流行的开源关系型数据库管理系统(RDBMS),基于 client-server 架构,使用 SQL 进行数据管理。由于其高性能、高可靠性、易用性及开源免费的特性,被广泛用于互联网应用(如 Facebook,Twitter,淘宝等)作为数据存储层。
- 官网:https://www.mysql.com
- 下载地址:https://dev.mysql.com/downloads/mysql/
- 部分工具仓库:https://github.com/mysql
- 历史版本下载地址:https://downloads.mysql.com/archives/community/
三、相关知识
3.1 事务隔离级别
事务的四大特性 ACID(原子性、一致性、隔离性、持久性),为了解决并发事务带来的问题(脏读、不可重复、幻读),SQL 标准定义了四种隔离级别。
|-----------------------|------------------------------|----|-------|-----------------|
| 隔离级别 | 描述 | 脏读 | 不可重复读 | 幻读 |
| Read Uncommitted 读未提交 | 一个事务可以读取另一个未提交事务的数据 | ✅ | ✅ | ✅ |
| Read Committed 读已提交 | 一个事务只能读取已经提交的事务的数据(Oracle默认) | ❌ | ✅ | ✅ |
| Repeatable Read 可重复读 | 同一事务中多次读取的结果一致(InnoDB 默认) | ❌ | ❌ | ✅ InnoDB多数场景可避免 |
| Serializable 串行化 | 强制事务串行执行 | ❌ | ❌ | ❌ |
3.2 MVCC(多版本并发控制)原理
MVCC 是 InnoDB 实现 Read Committed 和 Repeatable Read 隔离级别的核心机制,它通过保存数据在某个时间点的快照,使得读操作不需要加锁,大大提高了并发性能。
核心组成:
- 隐藏字段:InnoDB 会给每行数据添加三个隐藏字段:
- DB_TRX_ID:最近修改(或插入)该行数据的事务 ID;
- DB_ROLL_PTR:回滚指针,指向 Undo Log 中上一个版本的记录;
- DB_ROW_ID:隐藏的主键(如果表没有主键)。
- Undo Log(回滚日志):当事务修改数据时,MySQL 会将旧数据写入 Undo Log,通过回滚指针,形成一条版本链。
- Read View(读视图):事务进行快照读时产生的读视图,它决定了事务能看到版本链中的哪条数据。
- m_ids:生成 Read View 时,当前系统中活跃(未提交)的事务 ID 列表;
- min_trx_id:活跃事务中最小的 ID;
- max_trx_id:系统应该分配给下一个事务的 ID。
RC 与 RR 在 MVCC 上的区别:
- Read Committed:在每一次进行普通 Select 操作前都会生成一个新的 Read View,所以它能读到别的事务刚刚提交的数据。
- Repeatable Read:只在事务开启后的第一次 Select 操作前生成 Read View,之后复用这个 Read View,所以即使别的事务提交了修改,当前事务看到的依然是旧版本,从而实现了"可重复读"。
3.3 MySQL 的"三大日志"
MySQL 的数据安全和主从复制依赖于日志系统,最重要的是 Redo Log、Undo Log 和 Binlog。
- Redo Log(重做日志)- 物理日志
- 作用:保证事务的持久性(Durability),实现 Crash-safe 能力。
- 原理:WAL(Write-Ahead Logging)技术,先写日志,再写磁盘。
- 特点:
- InnoDB 存储引擎层特有的。
- 记录的是"在某个数据页上做了什么修改"。
- 是循环写的,固定大小,写满后需要擦除旧记录(Checkpoint)。
- Undo Log(回滚日志)- 逻辑日志
- 作用:保证事务的原子性(Atomicity)和实现 MVCC。
- 原理:记录数据的逻辑变化。例如执行一条 INSERT,Undo Log 就记录一条 DELETE;执行 UPDATE,就记录相反的 UPDATE。
- 场景:事务回滚时,通过 Undo Log 将数据恢复到修改前的样子。
- Binlog(归档/二进制日志)- 逻辑日志
- 作用:用于主从复制和数据恢复(如误删库后的恢复)。
- 特点:
- 是 MySQL Server 层实现的,所有引擎都可以使用。
- 是追加写的,不会覆盖旧日志。
- 记录的是 SQL 语句的原始逻辑(如 Statement 格式)或行数据的变更(Row 格式)。
四、面试问题
4.1 为什么 InnoDB 选择 B+ 树作为索引结构,而不是 B 树或 Hash
- Hash 查询效率极高,但不支持范围查询和排序;
- B 树的每个节点都存储数据,B+ 树只有叶子结点存储数据,非叶子结点只存索引
- 非叶子结点能容纳更多索引,磁盘 I/O 次数更少;
- B+ 树的叶子结点通过双向链表连接,范围查询时只需遍历链表,而 B 树需要进行中序遍历。
4.2 聚簇索引和非聚簇索引
- 聚簇索引
- 数据行和相邻的键值紧凑地存储在一起;
- InnoDB 的主键索引就是聚簇索引,叶子结点存储的是整行数据;
- 一张表只能有一个聚簇索引。
- 非聚簇索引
- 叶子节点存储的是索引列的值和主键 ID;
- 回表:如果通过二级索引查询非索引列的数据,需要先拿到主键 ID,再去聚簇索引(主键索引)中查找完整的行数据,这个过程叫回表。
4.3 最左前缀原则
假设有一个联合索引(a, b, c),查询条件必须从最左边列开始匹配。
- 如果查询条件是 where a=1 and b=2,命中索引;
- 如果查询条件是 where b=2 and c=3,不命中索引;
- 如果查询条件是 where a=1 and c=3,a 列命中索引,c 列不命中索引;
- 如果遇到范围查询(>, <, between, like),停止匹配后续列,查询条件是 where a=1 and b>2 and c=3,a 和 b 命中索引,c 不命中索引。