MySQL常见考点
这篇适合用于互联网大厂程序员面试前突击复习。重点不是“知道名词”,而是能把每个考点讲成一段完整答案。
目录
一页速记总表
| 分类 | 高频考点 | 面试常问 | 记忆点 |
|---|---|---|---|
| 存储引擎 | InnoDB、MyISAM 区别 | 为什么线上基本都用 InnoDB? | InnoDB = 事务 + 行锁 + 外键 + 崩溃恢复 |
| 索引 | 聚簇索引、二级索引、联合索引、覆盖索引 | 联合索引为什么要遵守最左前缀? | 最左匹配,中间不断,范围后降效 |
| 优化 | Explain、回表、索引下推、慢 SQL | SQL 为什么没走索引? | 先看过滤,再看排序,再看回表 |
| 事务 | ACID、隔离级别、幻读 | RR 为什么还能防幻读? | Undo 保旧,ReadView 判可见,Next-Key 防插入 |
| 并发 | 行锁、间隙锁、临键锁、死锁 | 死锁是怎么产生的? | 资源争抢 + 加锁顺序不一致 |
| 日志 | redo log、undo log、binlog | redo 和 binlog 有什么区别? | redo 保数据,binlog 保归档 |
| 主从 | 主从复制、读写分离、主从延迟 | 为什么会主从不一致? | 主写 binlog,从拉 relay log,再回放 |
| 设计 | 三大范式、反范式、分库分表 | 什么时候要分库分表? | 单表过大、并发过高、单机到顶 |
MySQL 架构与存储引擎
1. MySQL 基本架构
可以先把 MySQL 理解成两层:
- Server 层:连接器、分析器、优化器、执行器
- 存储引擎层:负责真正读写数据,最常见的是
InnoDB
记忆点
Server 层做解析和调度,存储引擎层做存取和落盘- 面试回答时,先讲“分层”,再讲“引擎”
2. InnoDB 和 MyISAM 的区别
这是老牌高频题,建议直接背表格式表达。
| 对比项 | InnoDB | MyISAM |
|---|---|---|
| 事务 | 支持 | 不支持 |
| 锁 | 行锁 | 表锁 |
| 外键 | 支持 | 不支持 |
| 崩溃恢复 | 支持 | 弱 |
| 索引组织 | 聚簇索引 | 非聚簇 |
| 适用场景 | OLTP、高并发写入 | 读多写少、历史场景 |
高频结论
- 线上业务库几乎默认选择
InnoDB - 因为它支持事务、行级锁、MVCC、崩溃恢复,更适合互联网高并发场景
记忆点
线上选 InnoDB,不是因为快,而是因为稳
索引
索引是 MySQL 面试的绝对核心,很多大厂一面二面都会深挖。
1. 什么是索引
索引的本质是帮助数据库快速定位数据的数据结构。MySQL 的 InnoDB 默认使用 B+Tree。
为什么不用普通二叉树或红黑树?
- 二叉树层高太高,磁盘 IO 多
- 红黑树虽然平衡,但分叉少,仍然会导致树高较高
B+Tree一个节点能存很多键值,树更矮,范围查询也更友好
记忆点
索引不是为了排序发明的,是为了减少查找成本B+Tree 适合磁盘,Hash 适合等值
2. 聚簇索引和二级索引
InnoDB 中,主键索引就是聚簇索引,数据行本身就存放在主键索引叶子节点上。
- 聚簇索引叶子节点:存整行数据
- 二级索引叶子节点:存索引列值 + 主键值
所以通过二级索引查整行数据时,往往要先找到主键,再回到聚簇索引中取完整数据,这个过程叫 回表。
记忆点
主键树挂整行,二级树挂主键查二级索引后再查主键树 = 回表
3. 覆盖索引
如果查询的列,刚好都在索引里,就不需要回表,这就是覆盖索引。
例如:
1 | SELECT id, name |
如果存在联合索引 (age, name),再加上主键 id 也能从索引中拿到,那么可能直接覆盖,不再回表。
记忆点
能在索引里拿全,就别回表- 覆盖索引常用于优化查询列表字段过多的问题
4. 联合索引与最左前缀原则
联合索引例如 (a, b, c),能使用的前提是从左往右连续匹配。
可用情况:
aa, ba, b, c
可能部分可用或失效的情况:
- 只查
b或c a用范围查询后,再利用b、c的能力会下降
经典口诀
最左匹配,中间不断,范围后降效
这句话几乎可以直接背。
5. 索引失效常见场景
高频失效点建议直接记:
- 对索引列做函数计算,例如
DATE(create_time) - 对索引列做表达式运算,例如
age + 1 = 30 - 隐式类型转换,例如字符串列和数字比较
- 以
%abc开头的模糊匹配 - 联合索引不满足最左前缀
- 使用
OR且其中一部分条件无法走索引
记忆点
索引列要保持“干净”- 所谓干净,就是不要在索引列上做函数、运算、类型转换
6. 什么情况下要建索引
适合建索引的字段:
- 高频作为查询条件的字段
- 高频用于排序、分组的字段
- 多表关联中的关联字段
- 区分度较高的字段
不适合建索引的字段:
- 区分度很低,比如性别
- 更新非常频繁的字段
- 很长的大字段
记忆点
查询多、筛选强、排序多、关联多,就考虑建索引写多、重复高、字段大,不要乱建索引
SQL 执行过程与优化
1. 一条 SQL 的执行过程
可以按下面顺序回答:
- 客户端先连接到 MySQL
- Server 层进行词法分析、语法分析
- 优化器选择执行计划
- 执行器调用存储引擎
- 存储引擎返回数据
记忆点
连接器 -> 分析器 -> 优化器 -> 执行器 -> 存储引擎
2. Explain 重点看什么
常见字段:
type:访问类型,性能从好到差大致是system > const > eq_ref > ref > range > index > ALLkey:实际使用的索引rows:预估扫描行数Extra:额外信息,比如Using index、Using filesort、Using temporary
重点理解
Using index通常说明走了覆盖索引Using filesort说明排序无法直接利用索引Using temporary常见于分组、排序不合理
记忆点
先看 type,再看 key,再看 rows,最后看 Extra
3. 慢 SQL 优化思路
一套标准回答模板:
- 先用慢查询日志或监控找到 SQL
- 用
EXPLAIN分析执行计划 - 看是否命中合适索引
- 看是否存在回表、排序、临时表
- 看 SQL 是否能改写
- 不行再考虑表结构调整、分库分表、缓存
记忆点
优化 SQL,不是上来就加索引,而是先看执行计划
4. 常见优化手段
- 避免
SELECT * - 分页使用延迟关联或基于主键翻页
- where、order by、group by 尽量共用索引
- 小表驱动大表
- 批量插入代替单条插入
- 合理控制事务大小
高频追问
为什么不建议深分页?
- 因为
LIMIT offset, size的 offset 很大时,MySQL 仍然要先扫描并丢弃前面的数据,成本很高
记忆点
深分页慢,不是返回慢,是跳过慢
事务与隔离级别
1. ACID
事务四大特性:
Atomicity原子性:要么都成功,要么都失败Consistency一致性:事务前后数据满足约束Isolation隔离性:并发事务之间互不干扰Durability持久性:提交后数据不丢
记忆点
A 原子,C 一致,I 隔离,D 持久
2. 四种隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
读未提交 RU |
可能 | 可能 | 可能 |
读已提交 RC |
不会 | 可能 | 可能 |
可重复读 RR |
不会 | 不会 | 理论上可能,InnoDB 中被大幅抑制 |
串行化 Serializable |
不会 | 不会 | 不会 |
MySQL InnoDB 默认隔离级别是 RR。
3. 脏读、不可重复读、幻读
- 脏读:读到了别人还没提交的数据
- 不可重复读:同一事务内,两次读同一行结果不一致
- 幻读:同一事务内,两次按条件查询,记录条数不一致
记忆点
脏读看的是“未提交内容”不可重复读看的是“同一行变了”幻读看的是“符合条件的行数变了”
MVCC
MVCC 是 MySQL 面试里的难点,但也是非常拉开差距的地方。
1. MVCC 是什么
MVCC 即多版本并发控制,让读操作尽量不加锁,通过读取数据的历史版本来提升并发能力。
它主要依赖:
undo log- 隐藏字段
Read View
2. Read View 做了什么
可以简单理解为:事务在读数据时,MySQL 会拿到一个“可见性快照”,判断某条记录版本对当前事务是否可见。
你不必在面试里把源码级细节背死,但至少要会说:
- 每次更新不会直接覆盖老版本,而是通过
undo log保留旧版本链 - 一致性读会根据
Read View判断该读哪个版本
记忆点
undo log 存老版本,Read View 决定看哪个版本
3. RC 和 RR 在 MVCC 上的差异
RC:每次普通select都可能生成新的Read ViewRR:事务第一次一致性读生成Read View,后续复用,所以可重复读
一句话记忆
RC 是句级快照,RR 是事务级快照
锁机制
1. 行锁、表锁、间隙锁、临键锁
- 行锁:锁住某一行记录
- 表锁:锁住整张表
- 间隙锁:锁住索引记录之间的区间,防止插入
- 临键锁:
记录锁 + 间隙锁
InnoDB 的行锁是基于索引实现的,如果查询没走索引,可能退化成较大范围的锁,甚至看起来像表锁效果。
记忆点
行锁锁的不是行本身,而是索引上的记录
2. 为什么会有幻读,MySQL 怎么解决
在当前读场景下,单靠 MVCC 不够,还要借助间隙锁/临键锁来阻止其他事务插入满足条件的新记录。
所以常见面试回答可以这样说:
- 快照读主要靠
MVCC - 当前读主要靠
Next-Key Lock
记忆点
快照读靠版本,当前读靠加锁
3. 死锁
死锁常见成因:
- 两个事务互相持有对方需要的锁
- 多个事务获取锁的顺序不一致
避免思路:
- 固定加锁顺序
- 尽量让事务短小
- 尽量走索引,缩小锁范围
记忆点
死锁的本质不是锁多,而是顺序乱
日志体系
日志体系是大厂非常爱问的一组题,往往和事务一起问。
1. redo log
redo log 是 InnoDB 特有的重做日志,用来保证事务提交后的持久性。
为什么需要它?
- 因为数据页在内存修改后,不会立刻刷盘
- 如果宕机,可能磁盘上的数据页还没来得及写回
- 这时可以靠 redo log 重放恢复
记忆点
redo 是“做过什么”,用于宕机恢复
2. undo log
undo log 记录数据修改前的旧版本,主要作用:
- 事务回滚
- 支持 MVCC
记忆点
undo 是“改之前什么样”
3. binlog
binlog 是 MySQL Server 层的归档日志,常用于:
- 主从复制
- 数据恢复
- 审计
和 redo log 的区别:
- redo log 是 InnoDB 引擎层日志
- binlog 是 Server 层日志
- redo log 偏物理
- binlog 偏逻辑
记忆点
redo 保持库不坏,binlog 负责传出去
4. 两阶段提交
当事务提交时,为了保证 redo log 和 binlog 一致,MySQL 会采用两阶段提交。
简化理解:
- 写 redo log,状态为 prepare
- 写 binlog
- 提交 redo log
为什么要这样做?
- 避免只写了其中一个日志,导致主从复制和数据恢复出现不一致
记忆点
先 prepare,再写 binlog,最后 commit redo
主从复制与高可用
1. 主从复制基本流程
高频回答模板:
- 主库写入数据
- 主库记录
binlog - 从库 IO 线程拉取主库
binlog - 写入从库
relay log - 从库 SQL 线程回放
relay log
记忆点
主写 binlog,从拉 relay log,再重放
2. 主从延迟原因
常见原因:
- 从库执行能力弱于主库写入速度
- 大事务回放慢
- 从库还有查询压力
- 网络延迟
常见应对:
- 避免大事务
- 提升从库配置
- 关键读请求走主库
- 监控复制延迟
记忆点
主从延迟,本质是从库追不上主库
3. 读写分离的风险
最大风险是:
- 主库刚写,从库还没同步完成,用户立刻去从库读取时读到旧数据
这就是常说的“延迟读”或“读写不一致”。
常见解决方案:
- 强一致读走主库
- 写后短时间内读主库
- 利用中间件做路由控制
数据库设计高频考点
1. 三大范式
- 第一范式:列不可再分
- 第二范式:非主属性完全依赖主键
- 第三范式:非主属性不传递依赖主键
但真实业务里经常会适度反范式,以提升查询性能。
记忆点
范式保规范,反范式保性能
2. 为什么不建议使用过长字符串做主键
因为主键是聚簇索引,主键越大:
- 主键索引更大
- 二级索引也会更大
- 页能装下的数据更少
- IO 成本更高
所以通常推荐:
- 自增主键
- 雪花 ID
记忆点
主键一大,整棵索引树都跟着胖
3. 什么时候需要分库分表
典型信号:
- 单表数据量过大
- 单机存储到瓶颈
- 并发量过高
- 单库成为系统瓶颈
分库分表带来的问题:
- 分布式事务
- 跨库 join
- 全局 ID
- 分页与排序复杂
记忆点
分库分表解决容量和并发,也引入复杂度
面试高频追问清单
下面这些题,出现频率非常高,建议逐条能讲 1 到 3 分钟。
索引类
- 为什么 MySQL 索引选择 B+Tree?
- 聚簇索引和非聚簇索引的区别是什么?
- 什么是回表?什么是覆盖索引?
- 联合索引为什么要遵守最左前缀?
- 索引下推了解吗?
- 什么情况下索引会失效?
事务类
- ACID 分别是什么?
- MySQL 默认隔离级别是什么?
- 什么是脏读、不可重复读、幻读?
- RC 和 RR 的区别是什么?
- MVCC 是怎么实现的?
锁类
- 行锁为什么依赖索引?
- 什么是间隙锁?什么是临键锁?
- InnoDB 如何避免幻读?
- 死锁是怎么发生的?怎么排查?
日志类
- redo log 和 binlog 的区别?
- undo log 的作用是什么?
- 两阶段提交是为了解决什么问题?
- 为什么提交事务后不一定立刻刷数据页?
架构类
- 主从复制原理是什么?
- 主从延迟怎么解决?
- 分库分表什么时候做?
- 读写分离有什么坑?
背诵口诀
如果你想在面试前一天快速过一遍,可以直接背下面这些短句。
1. 索引口诀
最左匹配,中间不断,范围后降效。
主键树挂整行,二级树挂主键。
能覆盖不回表,索引列要干净。
2. 事务口诀
RC 句级快照,RR 事务快照。
undo 存旧版本,Read View 判可见。
快照读靠 MVCC,当前读靠 Next-Key Lock。
3. 日志口诀
redo 保持久,undo 保回滚,binlog 保归档。
先 prepare,再写 binlog,最后提交 redo。
4. 调优口诀
先看慢日志,再看 Explain。
先看 type,再看 key,再看 rows,最后看 Extra。
优化不是乱加索引,而是减少扫描、减少回表、减少排序。
5. 架构口诀
主写 binlog,从拉 relay log,再重放。
分库分表抗规模,也会带来分布式复杂度。
最后怎么答得像大厂候选人
面试官问 MySQL,最好不要只给“定义式答案”,而要按下面这个顺序讲:
- 先给一句结论
- 再讲原理
- 再补一个使用场景或线上经验
- 最后补一句优缺点或注意事项
例如回答“为什么联合索引要遵守最左前缀”,可以按这个模板:
- 结论:联合索引底层按索引列从左到右有序组织,所以必须尽量从最左列开始匹配
- 原理:B+Tree 节点比较时先比较第一列,再比较第二列、第三列
- 场景:如果直接跳过最左列,后面的有序性通常无法被单独利用
- 注意点:遇到范围查询后,后续列继续利用索引排序和过滤的能力会下降
这类回答会明显比“只背定义”更像真正理解过。