MySQL常问核心知识点 + 八股文 + 场景题

发布于:2025-06-01 ⋅ 阅读:(1208) ⋅ 点赞:(0)

一、MySQL为什么使用B+树而不是B树?

✅ 面试八股文回答:

MySQL使用B+树作为索引结构,主要是为了提高磁盘IO性能。相比B树,B+树具有以下优势:

  1. 所有的值都在叶子节点,非叶子节点只存储键,不存储数据,单个节点能容纳更多索引项,提高扇出(fan-out),树的高度更小,查询更快。

  2. 叶子节点形成一个有序链表,适合范围查询或排序操作,只需顺序遍历叶子节点即可,效率更高。

  3. B+树在每次查找时都从根节点走到叶子节点,查询路径统一、稳定,有利于磁盘预读和缓存命中。

🎯 场景题:

你有一张百万级别的大表,需要频繁按某个字段范围查询,应该选择哪种索引结构?为什么?

👉 回答思路:使用B+树索引,因为它对范围查询友好,叶子节点有序链表结构可以顺序扫描。


二、MySQL加锁机制:有索引 vs 无索引 加什么锁?

✅ 面试八股文回答:

MySQL(InnoDB引擎)中,对于 SELECT ... FOR UPDATEUPDATE/DELETE 等加锁操作:

  • 有索引并且命中索引:加的是行锁(Record Lock),只锁住匹配到的行,效率高,支持高并发。

  • 无索引或索引未命中:加的是表锁间隙锁(Gap Lock)/临键锁(Next-Key Lock),因为需要扫描整张表,锁粒度大,可能导致阻塞。

特别注意:如果使用了范围条件且未命中索引,InnoDB会退化为间隙锁 + 行锁(Next-Key Lock),甚至是表锁,导致并发性能下降。

🎯 场景题:

你在用 UPDATE users SET age=30 WHERE name='张三',name字段没有加索引,会发生什么?

👉 回答思路:

  • 因为没有索引,InnoDB需要扫描整表来查找name='张三'的记录;

  • 因此会加表锁或对所有行加行锁,导致并发性能下降甚至出现死锁;

  • 解决方式是给name字段加索引,减少锁粒度。


三、MySQL事务四大特性(ACID)与隔离级别

✅ 面试八股文回答:
  • A:原子性(Atomicity)——事务中所有操作要么全部成功要么全部失败。

  • C:一致性(Consistency)——事务执行前后,数据都保持一致。

  • I:隔离性(Isolation)——多个事务之间互不干扰。

  • D:持久性(Durability)——事务提交后数据永久保存。

InnoDB默认隔离级别是:可重复读(Repeatable Read),通过MVCC机制解决幻读问题。

🎯 场景题:

为什么MySQL默认使用可重复读而不是串行化隔离级别?

👉 回答思路:

  • 可重复读可以避免大部分并发问题(不可重复读、幻读),但又比串行化隔离级别效率高。

  • 串行化虽然最安全但会严重降低并发性能。

  • 所以InnoDB通过MVCC机制,在可重复读下实现了高并发和一致性的平衡。


四、MySQL常见慢SQL优化分析步骤?

✅ 面试八股文回答:

慢SQL优化步骤包括:

  1. 使用 EXPLAIN 分析执行计划;

  2. 检查是否使用索引,是否走了全表扫描;

  3. 评估数据量是否合理,是否有冗余或重复查询;

  4. 是否可以使用覆盖索引(索引包含查询字段);

  5. 使用 慢查询日志SHOW PROFILE 分析执行时间;

  6. 考虑分库分表或缓存。

🎯 场景题:

你发现一个接口经常超时,SQL语句比较简单,但表很大,如何排查?

👉 回答思路:

  • 先用 EXPLAIN 看是否走索引;

  • 如果没走索引,分析原因(字段是否索引、条件写法问题如函数包裹);

  • SHOW INDEX 看索引情况;

  • 检查是否能使用覆盖索引;

  • 最后考虑加缓存、分表或归档历史数据。


五、聚簇索引 vs 非聚簇索引

✅ 面试八股文回答:
  • InnoDB的主键索引是聚簇索引,数据和索引存储在一起;

  • 辅助索引是非聚簇索引,只存储主键值,再通过主键定位数据(回表);

  • 所以查询效率:主键查询 > 覆盖索引 > 辅助索引(需要回表);

  • 如果有多个查询条件优先考虑使用主键或覆盖索引,避免回表。

🎯 场景题:

一张表经常根据 email 查询,这个字段有唯一约束,你该怎么设计索引?

👉 回答思路:

  • 如果email唯一,考虑将其设为主键,作为聚簇索引;

  • 否则,加唯一索引,并尽量让查询字段出现在索引中,构建覆盖索引避免回表。


📌 总结:MySQL八股点清单(用于突击面试)

知识点 面试高频问题 建议准备方式
索引 为什么用B+树?聚簇索引和非聚簇区别?回表是什么? 图解 + 口头复述
锁机制 行锁/表锁怎么加?有索引与无索引加什么锁?死锁怎么排查? 举例回答,推荐结合 SHOW ENGINE INNODB STATUS
执行计划 EXPLAIN 中各字段含义?type=ALL是好的吗? 记住type从好到坏的顺序
事务 ACID是什么?四种隔离级别?MySQL默认哪个? 对比幻读/脏读/不可重复读
MVCC 是什么?怎么实现?为什么默认可重复读还能避免幻读? 讲undo log和隐藏版本号
SQL优化 慢SQL怎么查?索引怎么建?什么时候用覆盖索引? 多练 EXPLAIN
索引失效 哪些写法会导致索引失效?(如函数包裹、!=) 举例练习
count(*)优化 为什么 count(*) 这么快? 了解聚簇索引原理

✅ MySQL高频面试问题总结性答案(建议背诵)


1. 为什么MySQL索引使用 B+ 树而不是 B 树?

答:
MySQL使用B+树作为索引,是为了提高查询效率:

  • B+树非叶子节点不存储数据,单节点能容纳更多键值,扇出高、树高度低,磁盘IO少;

  • 所有数据只存在叶子节点,叶子节点之间通过链表连接支持范围查询效率更高;

  • 查询必须走到叶子节点,路径固定,更利于缓存与预读优化


2. 有索引和无索引时,加的锁有什么区别?

答:

  • InnoDB默认使用行级锁

  • 如果 有索引且命中索引:加的是行锁

  • 如果 无索引或索引没命中:可能加表锁或大范围的间隙锁(Gap Lock),影响性能;

  • 在范围查询下,还可能加 Next-Key Lock(间隙锁 + 行锁)


3. InnoDB 为什么默认隔离级别是可重复读?

答:

  • 可重复读能解决不可重复读问题,还通过MVCC解决幻读问题;

  • 比串行化性能高,比读已提交更安全;

  • 兼顾数据一致性和并发性能,是InnoDB中最实用的隔离级别。


4. MySQL 行锁、表锁、间隙锁分别是什么?

答:

  • 行锁(Record Lock):锁住某一行数据,粒度小,效率高;

  • 表锁:锁住整张表,其他线程不能对其做任何修改操作;

  • 间隙锁(Gap Lock):锁住某个索引值之间的区间,防止幻读;

  • Next-Key Lock:是行锁和间隙锁的组合,锁住"记录+区间"。


5. MVCC 是怎么实现的?

答:

MVCC通过以下两部分实现:

  • Undo Log:记录数据修改前的版本;

  • 隐藏字段:trx_id, roll_pointer

  • 查询时只读取小于当前事务版本号的数据,读写分离,无需加锁。

适用于 可重复读、读已提交 隔离级别,避免加锁,提高并发。


6. EXPLAIN 中 type 字段各个值代表什么?

答(从好到差):

  • system > const > eq_ref > ref > range > index > ALL

  • ALL:全表扫描,性能最差;

  • ref/range:表示使用了索引;

  • 优化目标是让 type 尽量在 ref 或更优级别。


7. 什么是覆盖索引?怎么优化查询用它?

答:

  • 覆盖索引:查询只访问索引,不需要回表

  • 索引字段包含了所有需要的字段;

  • 优化方式:将查询字段设计为联合索引的一部分,比如:index(name, age) 查询 select age where name=...


8. 回表操作是什么?为什么会影响性能?

答:

  • InnoDB的辅助索引不存储整行数据,只存主键;

  • 查询非索引字段时,需要通过主键再去聚簇索引里查一次,叫做回表

  • 回表是额外的I/O开销,多一次查找,性能变差。


9. 哪些情况会导致索引失效?

答:

  • 使用了 or

  • 使用函数包裹字段,如 WHERE DATE(create_time)

  • 索引字段有 !=<>

  • 隐式类型转换,如 WHERE id = '123'

  • 联合索引不满足最左前缀原则。


10. count(*)为什么很快?

答:

  • InnoDB会通过聚簇索引的页结构统计行数,不会实际读取每一行;

  • 对于MyISAM引擎,表有专门的计数器;

  • 但是加了WHERE条件,count性能会变差,因为必须扫描数据匹配。


网站公告

今日签到

点亮在社区的每一天
去签到