MySQL 面试高频 100 题
定位:面试题不是学习主线,是原理掌握后的检验手段——每道题都链接回对应的原理笔记 使用方法:先理解原理→再读面试题→用面试题自测,发现自己答不出的点→回去重新理解原理
一、架构与存储引擎
1.1 一条 SELECT 语句的执行过程?
考察点:MySQL 架构分层、各组件的职责
→ 详阅 **MySQL架构总览**
答案要点:
- 连接器:认证 + 管理连接
- 查询缓存(8.0 前):命中则直接返回
- 分析器:词法分析 → 语法分析 → 语法树
- 优化器:选择索引、决定 JOIN 顺序、生成执行计划
- 执行器:调用存储引擎 API,循环读取行
- 存储引擎:从磁盘/内存读取数据
1.2 为什么 MySQL 需要分层架构?
考察点:架构设计思想、可插拔存储引擎
→ 详阅 **MySQL架构总览**
答案要点:解耦查询处理和数据存储;引擎可插拔;关注点分离——Server 层专注查询优化,引擎层专注数据读写。
1.3 InnoDB 和 MyISAM 的核心区别?
考察点:事务、锁、索引、崩溃恢复
→ 详阅 **存储引擎对比**
| 维度 | InnoDB | MyISAM |
|---|---|---|
| 事务 | ✅ ACID | ❌ |
| 锁粒度 | 行锁 | 表锁 |
| 聚簇索引 | ✅ 是 | ❌ 否 |
| 崩溃恢复 | ✅ Redo Log | ❌ repair table |
1.4 InnoDB 为什么这么快?
考察点:Buffer Pool、Change Buffer、预读
→ 详阅 **InnoDB架构**
答案要点:Buffer Pool 缓存热点数据减少磁盘 IO;Change Buffer 延迟合并二级索引写入;异步 IO + 预读机制。
1.5 Buffer Pool 的 LRU 为什么不是标准的?
考察点:全表扫描污染、Midpoint Insertion 策略
→ 详阅 **InnoDB架构** → 2.2 Buffer Pool
答案要点:标准 LRU 会被全表扫描污染(一次扫描把热数据挤出)。InnoDB 用 Midpoint Insertion:新页插入 5/8 位置(old 区域),1000ms 内再被访问才晋升到 young 区域。
二、索引与查询优化
2.1 为什么 MySQL 用 B+树做索引?
考察点:B+树 vs B树 vs 红黑树 vs 哈希
→ 详阅 **B+树索引结构**
答案要点:
- B+树内节点只存 key → 扇出大(~500)→ 树极矮(3-4 层存亿级数据)
- 叶子节点链表 → 范围查询 O(N)(不需要回溯)
- 对比:红黑树树高 log₂N(1 亿行 ≈ 27 层 IO);B 树内节点存数据扇出小且范围查询慢;哈希不支持范围
2.2 聚簇索引和二级索引有什么区别?
考察点:索引组织表、回表、覆盖索引
→ 详阅 **聚簇索引与二级索引**
答案要点:
- 聚簇索引:叶子节点存整行数据,数据和索引一体
- 二级索引:叶子节点存主键值,需要回表查完整行
- 覆盖索引:查询列全部在二级索引中 → 不需要回表
2.3 什么是回表?怎么避免?
→ 详阅 **聚簇索引与二级索引** → 2.3
答案要点:二级索引查到主键值→再去聚簇索引取完整行。避免方法:用覆盖索引(索引包含查询的所有列)。
2.4 最左前缀原则是什么?
考察点:联合索引的排序规则
→ 详阅 **索引优化策略**
答案要点:联合索引 (a,b,c),只有从第一列开始的连续前缀能用。因为 B+树按从左到右顺序排序。WHERE b=1 不能用到 (a,b,c) 索引。
2.5 什么是索引下推(ICP)?
→ 详阅 **索引优化策略** → 2.3
答案要点:在引擎层用索引列过滤数据,减少回表次数。Extra: Using index condition。如 WHERE name LIKE '张%' AND age=25——在二级索引层提前过滤 age=25,只有符合条件的行才回表。
2.6 EXPLAIN 的 type 列各个值什么意思?
→ 详阅 **EXPLAIN与查询优化**
从好到差:system > const > eq_ref > ref > range > index > ALL
2.7 Extra 出现 Using filesort 怎么办?
答案要点:说明排序无法走索引。解决方案——让 ORDER BY 的列加入索引。
三、SQL 与事务
3.1 MVCC 的实现原理是什么?
→ 详阅 **MVCC实现原理**
答案要点:每行有三个隐藏列(DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID);UPDATE 产生旧版本写入 Undo Log 形成版本链;事务第一次 SELECT 时创建 Read View,根据可见性规则从版本链中找到可见版本。
3.2 Read View 的可见性规则?
→ 详阅 **MVCC实现原理** → 2.3
| 条件 | 可见性 |
|---|---|
| DB_TRX_ID == creator_trx_id | ✅ 可见 |
| DB_TRX_ID < min_trx_id | ✅ 可见 |
| DB_TRX_ID >= max_trx_id | ❌ 不可见 |
| DB_TRX_ID IN m_ids | ❌ 不可见 |
| 其他 | ✅ 可见 |
3.3 RC 和 RR 在 MVCC 上的区别?
→ 详阅 **事务隔离级别**
答案要点:RC 每条语句创建新的 Read View(读到最新已提交数据),RR 整个事务复用第一个 Read View(事务内数据一致)。
3.4 不可重复读和幻读的区别?
→ 详阅 **事务隔离级别** → 2.1
| 对比维度 | 不可重复读 | 幻读 |
|---|---|---|
| 影响范围 | 同一行(UPDATE) | 结果集(INSERT/DELETE) |
| 如何解决 | MVCC 快照读 | MVCC + 间隙锁 |
3.5 ACID 分别由什么保证?
→ 详阅 **事务ACID实现**
答案要点:A=Undo Log(回滚)、I=MVCC+锁、D=Redo Log(WAL)、C=A+I+D+约束+应用逻辑。
3.6 为什么 WAL 快?
→ 详阅 **事务ACID实现** → 2.4
答案要点:Redo Log 是顺序追加写(~500MB/s),数据文件是随机写(~5MB/s)。顺序写比随机写快 10-100 倍。
四、锁机制
4.1 Row Lock、Gap Lock、Next-Key Lock 的区别?
→ 详阅 **行锁与间隙锁**
答案要点:Record Lock 锁单条索引记录;Gap Lock 锁间隙(防插入);Next-Key Lock = Record + Gap,锁定 (前一个值, 当前值]。
4.2 间隙锁的作用是什么?
答案要点:阻止其他事务在索引间隙中插入新行,RR 级别下防止幻读。
4.3 死锁怎么排查?
→ 详阅 **死锁分析与排查**
答案要点:SHOW ENGINE INNODB STATUS 查看 LATEST DETECTED DEADLOCK 部分。关注两个事务各持有和等待什么锁。
4.4 怎么避免死锁?
答案要点:固定资源访问顺序、缩短事务、RC 代替 RR(不加间隙锁)、直接加 X 锁(避免 S→X 升级)、应用层捕获 1213 错误重试。
五、日志系统
5.1 Redo Log 和 Binlog 的区别?
→ 详阅 **Redo Log** & **Binlog**
| 维度 | Redo Log | Binlog |
|---|---|---|
| 所在层 | InnoDB 引擎层 | Server 层 |
| 类型 | 物理日志(页+偏移+修改) | 逻辑/行日志 |
| 写入方式 | 循环写(固定大小) | 追加写(滚动) |
| 作用 | Crash Recovery(持久性) | 复制 + PITR |
5.2 为什么需要两阶段提交?
→ 详阅 **两阶段提交与崩溃恢复**
答案要点:保证 Redo Log 和 Binlog 的一致性。否则崩溃后可能出现"Redo Log 有但 Binlog 没有"或反之,导致主从不一致。
5.3 崩溃恢复的过程?
→ 详阅 **两阶段提交与崩溃恢复** → 2.3
答案要点:扫描 Redo Log 找到所有 prepare 状态的事务 → 检查 Binlog 中是否有对应 XID → 有则补提交,无则回滚。
5.4 Binlog 三种格式的优劣?
→ 详阅 **Binlog** → 2.1
答案要点:STATEMENT 日志小但不安全(时间函数等不确定);ROW 最安全但日志大;MIXED 自动切换但不完全可控。推荐 ROW。
六、高可用与架构
6.1 主从复制的三个线程分别做什么?
→ 详阅 **主从复制原理**
答案要点:Master Binlog Dump Thread(发送 Binlog);Slave IO Thread(接收写入 Relay Log);Slave SQL Thread(读取 Relay Log 重放)。
6.2 异步复制和半同步复制的区别?
答案要点:异步不等待从库(性能好、可能丢数据);半同步等待至少一个从库确认(更安全、略慢)。
6.3 复制延迟怎么解决?
答案要点:MTS 多线程复制(slave_parallel_workers)、避免大事务、从库拆分(专用复制/专用查询)。
6.4 分库分表的分片键怎么选择?
→ 详阅 **读写分离与分库分表**
答案要点:按访问频率最高的维度分片;确保 >90% 查询带分片键;数据分布均匀。
七、综合开放题
7.1 从库查询很慢,怎么排查?
考察点:系统性排查能力
答案要点:
SHOW PROCESSLIST看是否有长时间运行的查询SHOW SLAVE STATUS看Seconds_Behind_MasterEXPLAIN分析慢查询的执行计划- 检查从库的 Buffer Pool 命中率
- 如果延迟严重,检查 SQL 线程是否在重放大事务
7.2 一张表 1 亿行数据,如何优化查询?
考察点:系统性的优化思路
答案要点:
- 索引优化:检查现有索引是否合理,添加覆盖索引
- 分页优化:用游标分页代替 OFFSET 分页
- 读写分离:把查询分流到从库
- 数据归档:把历史数据迁移到归档表
- 分表:按时间或用户 ID 水平拆分
- 缓存:热点数据用 Redis 缓存
7.3 MySQL 死锁、主从延迟、全表扫描同时出现,先解决哪个?
答案要点:
- 全表扫描最优先——它的影响最大(占用大量 IO 和 CPU,可能引发其他问题)
- 主从延迟第二——结合业务容忍度判断是否紧急
- 死锁第三——如果是偶发死锁,应用层重试即可;如果是高频死锁则需要排查
📚 相关链接
- 综合解析:**综合真题解析**
- ← 返回 **设计文档**