# 05面试八股-Mysql篇
# 🟢 第一问
面试官:MySQL InnoDB 为什么用 B+树,不用 B 树或二叉树?
相比于二叉树来说,二叉树顺序插入时,会形成一条很长很深的树,效率相当于链表,红黑树虽然解决了这个问题,但是深度深时检索太慢。
相比于B树,占用相同空间的情况下,B树存储的结点更少,因为B树是每个结点都会存数据,而B+树只在叶子结点存数据,其余结点相当于存储的是索引,而且叶子结点存储的值形成一个环形链表,支持范围查询能力更强
# 🟡 第二问(追问)
面试官:什么是“回表”?什么情况下能避免回表?
回表:通过二级索引找到主键 ID → 再回到主键索引查完整行数据。
避免回表:
查询的时候,根据联合索引查出来了所需要的全部数据
# 🔴 第三问(深度追问)
面试官:为什么建议使用自增主键?UUID 做主键有什么问题?
自增主键的优势
避免页分裂
空间利用率高,能让数据填充率接近饱和
减少IO开销
UUID的劣势
UUID插入无序,如果插入到一个已经满了的页,会出现页分裂问题,页分裂会导致B+树重新平衡,浪费空间
占用空间大,会导致树增高,增大IO开销
# 🟢 第一问
面试官:联合索引 (a, b, c),哪些查询能用到索引?
全值匹配我最爱,最左前缀要遵守;带头大哥不能死,中间兄弟不能断;索引列上不计算,范围之后全失效。
| SQL | 是否走索引 | 原因 |
|---|---|---|
WHERE a = 1 | ✅ | 从最左列开始 |
WHERE a = 1 AND b = 2 | ✅ | (a,b) 匹配 |
WHERE a = 1 AND b = 2 AND c = 3 | ✅ | 全部匹配 |
WHERE b = 2 AND c = 3 | ❌ | 跳过了 a,无法走索引 |
WHERE a = 1 AND c = 3 | ⚠️ 部分 | 只用 a 的部分,c 用不到 |
WHERE a = 1 AND b > 2 AND c = 3 | ⚠️ 部分 | 范围查询 b> 导致 c 用不到 |
# 🟡 第二问(追问)
面试官:WHERE a = 1 AND b IN (2,3) AND c = 4 能用到几列索引?
能用到
(a, b, c)全部三列IN在优化器眼里通常当作等值查询处理(不是范围查询)所以 c 依然能用到索引
这和
b > 2不同,IN是离散值集合,不走范围中断逻辑
# 🔴 第三问(深度追问)
面试官:MySQL 针对最左前缀有没有优化?比如 WHERE b = 2 AND a = 1 能走索引吗?
💡 答案要点
能走。MySQL 优化器会做条件重排:
你写的
b = 2 AND a = 1优化器自动变成
a = 1 AND b = 2然后正常使用联合索引
但是:索引列必须存在,不能跳过中间列(比如只查 b 和 c,没有 a 就没办法)
# 🟢 第一问
EXPLAIN id字段
id 相同,执行顺序从上到下;id 不同,值越大,越先执行
面试官:EXPLAIN 结果里的 type 字段有哪些值?从好到差怎么排?
system(系统表)>const(主键索引)>eq_ref(多表查询主键或唯一索引)>ref(二级索引)>range(索引范围查询)>index(扫描整个索引)>ALL(全表扫描)
# 🟡 第二问(追问)
面试官:key 和 rows 分别代表什么?rows 越小越好吗?
key:实际应用的索引
rows:索引扫描的行数,一般为估算值
一般越小越好,但也要结合type来判断,如果type为const类型,即使rows大一点,性能也依旧强悍,如果type为all类型,即使是几千行的并发数据,性能也不是很好。
同时也要结合Extra额外信息的情况,如果Extra为索引覆盖,说明他已经找到了全部所需要的数据,不需要再去进行回表查询了,即使是rows大,效率也很高
补充知识Extra可能出现的值
sing index(覆盖索引 - 极好)
- 含义:表示查询使用了覆盖索引。MySQL 只需要在索引树上就能获取到所有需要的数据,完全不需要回表去查聚簇索引。
- 性能:这是性能优化的理想状态,I/O 开销极小。
Using filesort(文件排序 - 需警惕)
- 含义:表示 MySQL 无法利用索引的有序性来完成排序(
ORDER BY)或分组(GROUP BY)操作,必须在内存或磁盘中进行额外的排序运算。 - 性能:如果数据量小,在内存中排序还好;如果数据量大,会触发磁盘临时文件排序,性能会急剧下降。通常需要优化索引来消除它。
- 含义:表示 MySQL 无法利用索引的有序性来完成排序(
Using temporary(使用临时表 - 需警惕)
- 含义:表示 MySQL 在执行过程中使用了内部临时表来保存中间结果。常见于
GROUP BY、DISTINCT或者复杂的UNION查询中。 - 性能:和
Using filesort一样,如果临时表过大导致在磁盘上创建,性能会非常差。
- 含义:表示 MySQL 在执行过程中使用了内部临时表来保存中间结果。常见于
Using where(回表过滤 - 常见)
- 含义:表示 MySQL 在存储引擎层取出数据后,在 Server 层使用了
WHERE子句进行了条件过滤。 - 性能:这通常意味着发生了回表(即先通过索引找到主键,再回聚簇索引取完整行数据,最后进行过滤)。如果出现
Using where且没有Using index,说明索引没有完全覆盖查询条件。
- 含义:表示 MySQL 在存储引擎层取出数据后,在 Server 层使用了
Using index condition(索引下推 - 较好)
- 含义:这是 MySQL 5.6 引入的优化(ICP)。表示虽然不能完全通过索引定位数据,但 MySQL 把部分
WHERE条件下推到了存储引擎层,在索引遍历的过程中就直接过滤掉了一部分不满足条件的数据,从而减少了回表的次数。 - 性能:比单纯的
Using where效率更高,因为它减少了不必要的回表操作。
- 含义:这是 MySQL 5.6 引入的优化(ICP)。表示虽然不能完全通过索引定位数据,但 MySQL 把部分
# 🔴 第三问(场景题)
面试官:给你一个慢 SQL,你用 EXPLAIN 看到 type=ALL 且 Extra=Using filesort,你的优化思路是什么?
type=All说明没走索引,fileSort数据量大时,速度很慢
优化思路:
先根据where 条件,创建索引
如果有Order by,尽量让索引,顺带附带顺序
索引本身是有序的,如果能利用索引顺序,MySQL 就不需要额外
Using filesort
# 🟢 快速自测
问:如何查看当前 MySQL 的事务隔离级别?怎么修改?
select @@transaction_isolation;
show variables like "transaction_isolation";
set global transaction isolation level read committed ;
2
3
4
5
# 🟢 开放题
面试官:一张表几千万数据,查询越来越慢,你会怎么优化?(说出至少 3 种方案)
大字段拆表,独立成一个表
分库分表
建索引
分页优化
| 优先级 | 方案 | 说明 |
|---|---|---|
| 1 | 加索引 | 先检查慢查询,分析 WHERE、ORDER BY、JOIN 字段 |
| 2 | 分页优化 | 避免 OFFSET 大偏移量:改用“游标分页”(WHERE id > last_id LIMIT N)记住上一页查询完的位置,直接往后查(天机学堂学到过) |
| 3 | 读写分离 | 主库写,从库读 |
| 4 | 分库分表 | 水平拆分(Sharding-JDBC / MyCat) |
| 5 | 冷热分离 | 历史数据归档到另一个表或 OSS |
| 6 | 字段优化 | 避免 SELECT *;大字段(TEXT/BLOB)单独拆表 |
| 7 | 数据类型优化 | 能用 INT 不用 VARCHAR;能用 TINYINT 不用 INT |
# 🟢 第一问
面试官:如何开启慢查询日志?怎么分析?
-- 1. 开启慢查询日志
SET GLOBAL slow_query_log = ON;
-- 2. 设置阈值(超过 1 秒就算慢)
SET GLOBAL long_query_time = 1;
-- 3. 查看慢查询日志位置
SHOW VARIABLES LIKE 'slow_query_log_file';
2
3
4
5
6
分析工具:
mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log
# 🟡 第二问(场景题)
面试官:生产环境突然响应变慢,你怀疑是数据库问题,你的排查步骤是什么?
show processlist是否有锁等待和慢查询日志在跑开启慢查询日志,找出最慢的几条sql
explain分析,判断是否是索引失效
检查是否是锁竞争(
SHOW ENGINE INNODB STATUS看锁信息)检查服务器资源(CPU、IO)