MySQL
大约 8 分钟Java八股文Java八股文MySQL
阅读提示
建议先打透 4 条主线:执行流程、索引、事务与锁、日志与高可用。
回答优化题时优先使用“定位 -> 原因 -> 方案 -> 验证”四步结构。
本文以 MySQL 8.4 LTS、InnoDB 为基线;MyISAM 对比另行标明。隔离级别和复制并行度可配置,排查时应以实例实际配置为准。
推荐训练法
- 第一遍建立题目地图,先不追细节。
- 第二遍吃透高频:索引、隔离级别、MVCC、日志。
- 第三遍按线上场景口述:慢 SQL、死锁、主从延迟。
1、一个查询语句是怎么执行的?
回答提示:
- 连接器(鉴权) -> 解析器(词法/语法) -> 优化器(执行计划) -> 执行器(调用存储引擎)。
参考回答:
- 关键是“优化器决定怎么查”,不是“按 SQL 写的顺序机械执行”。
2、InnoDB 和 MyISAM 有什么区别?
- InnoDB 支持事务,MyISAM 不支持。
- InnoDB 支持行锁,MyISAM 主要是表锁。
- InnoDB 支持外键,MyISAM 不支持。
- InnoDB 使用聚簇索引。
3、什么是索引?为什么能加速查询?
回答提示:
- 索引相当于“有序目录”,减少扫描范围。
- 通过更少的磁盘 IO 定位目标记录。
4、B+ 树为什么适合数据库索引?
- 多路平衡树,层高低,磁盘 IO 次数少。
- 叶子节点有序且可链式遍历,范围查询性能好。
- 内部节点只存键值,单页可容纳更多索引项。
5、聚簇索引和非聚簇索引的区别
回答提示:
- 聚簇索引:叶子页保存整行记录,按聚簇键组织;这是索引的逻辑顺序,不代表磁盘文件物理连续。
- InnoDB 优先选主键;没有主键时选第一个所有列均为 NOT NULL 的 UNIQUE 索引;仍没有时生成隐藏行 ID 作为聚簇键。
- 二级索引(非聚簇):叶子记录包含二级索引列和聚簇键(通常为主键),可能回表。
官方资料:Clustered and Secondary Indexes。
6、什么是回表?如何减少回表?
- 二级索引查到主键后,再到主键索引取整行,叫回表。
- 尽量使用覆盖索引(查询列都在索引里)。
- 控制
select *,只查必要列。
7、什么是最左前缀匹配原则?
回答提示:
- 联合索引从最左列开始连续命中才更容易走索引。
- 跳过前导列通常会导致索引效果下降。
8、哪些情况会导致索引失效?
这些情况通常影响普通 B+ 树索引的定位能力,但不等于“任何索引都不能使用”:
- 对索引列做函数/计算,普通列索引通常不能直接定位表达式结果;匹配的函数索引是例外。
- 隐式转换需看方向,例如字符串索引列与数字比较可能无法利用该索引定位;不能把所有类型转换一概而论。
- 前导模糊查询(如
%abc)通常不能构造 B+ 树范围,但仍可能扫描覆盖索引。 - 联合索引缺少最左列条件,通常无法常规定位;8.4 在满足条件时可选择 Skip Scan。是否选择索引还取决于成本估算。
例如索引 (a,b,c) 按元组排序,a=1 AND b>10 AND c=3 通常用 a,b 构造范围,c 仍可用于后续过滤,不能说它“完全失效”。用 EXPLAIN 判断实际访问路径。
官方资料:联合索引、范围优化与 Skip Scan。
9、事务的 ACID 分别是什么?
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
10、隔离级别有哪些?MySQL 默认是什么?
- Read Uncommitted
- Read Committed
- Repeatable Read(MySQL InnoDB 默认)
- Serializable
11、脏读、不可重复读、幻读分别是什么?
- 脏读:读到未提交数据。
- 不可重复读:同一事务两次读同一行结果不同。
- 幻读:同一事务重复查询同一条件时,因其他事务插入或删除,结果集合的成员发生变化;不只看行数。
12、什么是 MVCC?
回答提示:
- 多版本并发控制:InnoDB 通过记录中的事务信息、undo 版本链和 Read View 判断哪个版本对当前一致性读可见。
参考回答:
- 在 RC / RR 下,普通一致性读通常不加记录锁,因此可与写入并发;这不适用于
SELECT ... FOR UPDATE等锁定读,也不代表不会等待元数据锁。 - RR(默认)通常在事务第一次一致性读时建立快照,之后复用;不是一执行
BEGIN就建立快照。RC 每次一致性读建立新快照。事务始终能看到自己的修改。 - 读取时先检查当前记录版本是否可见;不可见则沿 undo 链寻找可见版本。锁定读、
UPDATE、DELETE不按同一个历史快照工作,因此不要把快照读与锁定读混用的结果都归为“可重复读失效”。
前提:已有 id=1,v=10;A 使用 RR,且没有修改该行
A: BEGIN; SELECT v WHERE id=1; → 10(首次一致性读建立快照)
B: UPDATE 同一行 SET v=20; COMMIT;
A: 再次普通 SELECT v WHERE id=1; → 10(RC 下此处为 20)
A: COMMIT;这是时序示意,省略表名,并非可直接执行的 SQL 脚本。RR 的范围锁定读通常用 next-key 锁阻止范围内插入;快照读则靠版本可见性保持结果,两者机制不同。
官方资料:Consistent Nonlocking Reads、InnoDB Locking。
13、InnoDB 常见锁有哪些?
- 记录锁:锁住索引记录,可分共享锁 S 和排他锁 X。
- 间隙锁(Gap Lock):主要阻止向索引间隙插入。
- 临键锁(Next-Key Lock):记录锁与该记录之前的间隙锁组合。
- 意向锁:表级 IS / IX,表达事务准备在表内加哪类行锁。
RR 下范围访问常用 next-key 锁;唯一索引完整等值命中已有记录时通常只需记录锁。RC 下通常不为搜索和扫描加间隙锁,但外键和重复键检查等仍有例外;锁范围取决于索引访问路径。
14、什么情况下会发生死锁?如何处理?
回答提示:
- 两个事务互相持有对方需要的锁。
- 处理方式:统一加锁顺序、缩小事务、降低持锁时间、失败重试。
15、delete、truncate、drop 的区别
delete:DML,可带条件;对 InnoDB,在提交前可回滚,自动提交后不能再用ROLLBACK撤销。MyISAM 不提供事务回滚。truncate:清空整表的 DDL,会隐式提交,不能由用户ROLLBACK撤销,通常比逐行删除快。drop:删除表结构和数据;普通表的DROP TABLE同样会隐式提交。临时表有单独规则,不能直接套用。
MySQL 8.4 的原子 DDL 是指 DDL 在故障恢复时整体成功或失败,并不意味着用户可用事务回滚 DDL。
官方资料:隐式提交语句。
16、redo log、undo log、binlog 的区别
- redo log:InnoDB 物理日志,保证崩溃恢复。
- undo log:逻辑回滚与 MVCC 历史版本。
- binlog:Server 层二进制日志,用于复制和配合基础备份做时间点恢复;可记录语句或行变更事件,不能理解为只记录原始 SQL。
17、为什么需要“两阶段提交”?
回答提示:
- 协调本机 redo log 与 binlog 的提交决定,避免崩溃恢复时两者对事务是否提交产生矛盾。它不保证异步副本已接收或应用,复制丢失窗口需另行分析;见日志与恢复专题。
18、什么是 Buffer Pool?
- InnoDB 的内存缓存区,缓存数据页和索引页。
- 命中 Buffer Pool 可以显著减少磁盘 IO。
19、慢 SQL 排查一般怎么做?
- 先看慢日志与执行频次。
- 用
EXPLAIN看执行计划(type、rows、extra)。 - 定位是否走索引、是否回表、是否临时表/文件排序。
- 优化后压测验证。
20、主从复制原理是什么?
- 主库写 binlog。
- 从库 IO 线程拉取 binlog 写 relay log。
- 从库应用 relay log 中的事务;单线程模型由 SQL applier 执行,多线程模型由 coordinator 分发给 worker。MySQL 8.4 默认
replica_parallel_workers=4,不能统一描述为只有一个回放线程。
普通异步复制中,主库提交成功不代表从库已经应用事务,因此刚写完立即读从库可能读到旧数据。
官方资料:Replication Threads。
21、主从延迟怎么治理?
- 读写分离时对强一致读回源主库。
- 缩短大事务,避免批量慢写。
- 优化从库硬件和并行回放能力。
22、为什么要分库分表?
- 单表/单库达到容量和吞吐瓶颈后,通过拆分提升扩展性。
23、分库分表常见问题有哪些?
- 分布式事务。
- 跨库 join 困难。
- 全局 ID 设计。
- 分页与排序复杂度提升。
24、如果单表千万级后变慢,一般怎么优化?
- 优化索引与 SQL。
- 冷热数据归档。
- 分区表或分库分表。
- 引入缓存与读写分离。
25、面试可直接复述模板
- 我做 MySQL 优化时,先通过慢日志和 EXPLAIN 定位瓶颈,再判断是索引问题、SQL 写法问题还是数据分布问题。
- 对高频查询优先做覆盖索引,减少回表和随机 IO。
- 对高并发场景会结合缓存、限流和读写分离,确保峰值流量下稳定性。
