MySQL作为目前最流行的关系型数据库之一,是后端开发、数据库运维等相关岗位面试的必考内容,掌握高频面试问题对应的知识点,能有效提升面试通过率。

一、索引相关常见问题
1. 什么是索引,它的作用是什么
索引是帮助MySQL高效获取数据的数据结构,类似于书籍的目录,通过索引可以快速定位到符合条件的数据行,避免全表扫描,从而提升查询效率。不过索引也会占用额外的存储空间,并且在数据增删改时会增加维护成本,所以需要根据实际业务场景合理创建索引。
2. B+树索引和哈希索引的区别是什么
两者的核心差异如下:
| 对比维度 | B+树索引 | 哈希索引 |
|---|---|---|
| 适用查询场景 | 支持范围查询、排序、模糊查询 | 仅支持等值查询 |
| 查询效率稳定性 | 查询效率稳定,树高度通常为3-4层 | 等值查询效率极高,但可能出现哈希冲突 |
| 有序性 | 叶子节点按索引键有序排列 | 无有序性 |
3. 什么情况下索引会失效
常见的索引失效场景包括:
- 对索引列使用函数或者进行运算,比如
where length(name) = 3 - 查询条件中使用不等于、not in、is not null
- like查询以通配符开头,比如
where name like '%test' - 字符串类型索引列查询时未加引号,导致隐式类型转换
- 联合索引未遵循最左前缀原则
二、事务相关常见问题
1. 事务的ACID特性分别指什么
ACID是事务的四个核心特性:
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败回滚,不会出现部分执行的情况
- 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏,数据状态是合法的
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不会被其他事务干扰,不同事务之间的操作是隔离的
- 持久性(Durability):事务提交后,对数据的修改是永久性的,即使数据库发生故障也不会丢失
2. MySQL的四种事务隔离级别分别是什么,各有什么问题
MySQL支持四种事务隔离级别,从低到高依次为:
- 读未提交(Read Uncommitted):一个事务可以读取到另一个事务未提交的数据,可能出现脏读、不可重复读、幻读问题
- 读已提交(Read Committed):一个事务只能读取到另一个事务已经提交的数据,解决了脏读问题,但可能出现不可重复读、幻读问题
- 可重复读(Repeatable Read):同一个事务中多次读取同一数据的结果是一致的,MySQL默认隔离级别,解决了脏读、不可重复读问题,InnoDB引擎通过间隙锁解决了幻读问题
- 串行化(Serializable):事务串行执行,完全隔离,解决了所有并发问题,但性能最低
3. 什么是脏读、不可重复读、幻读
- 脏读:事务A读取了事务B未提交的数据,之后事务B回滚,事务A读取到的就是无效数据
- 不可重复读:事务A多次读取同一数据,事务B在事务A读取过程中修改并提交了该数据,导致事务A两次读取的结果不一致
- 幻读:事务A按照某个条件查询数据,事务B插入了符合该条件的新数据并提交,事务A再次查询时发现了之前不存在的数据,就像出现了幻觉
三、SQL优化相关常见问题
1. 如何分析一条SQL的执行效率
可以使用EXPLAIN关键字分析SQL的执行计划,查看SQL的执行情况,重点关注以下字段:
- type:访问类型,从好到坏依次为system > const > eq_ref > ref > range > index > ALL,尽量避免出现ALL(全表扫描)
- key:实际使用的索引,如果为NULL说明没有使用索引
- rows:预估需要扫描的行数,数值越小越好
- Extra:额外信息,比如Using index表示覆盖索引,Using filesort表示需要额外排序,Using temporary表示使用临时表
示例分析语句如下:
-- 分析查询用户表中id为10的用户的执行计划 EXPLAIN SELECT * FROM user WHERE id = 10;
2. 大表分页查询优化方案有哪些
当表数据量很大时,limit offset, rows的分页方式在offset很大时效率极低,优化方案包括:
- 使用覆盖索引+子查询优化:先通过索引查询到主键,再关联原表查询数据,避免回表
- 基于自增主键分页:如果主键是自增的,可以使用
where id > 上一页最大id limit 每页数量的方式分页
优化示例如下:
-- 优化前的大分页查询 SELECT * FROM order_table LIMIT 100000, 10; -- 优化后的查询,假设id是自增主键 SELECT * FROM order_table WHERE id > (SELECT id FROM order_table ORDER BY id LIMIT 100000, 1) LIMIT 10;
四、存储引擎相关常见问题
1. InnoDB和MyISAM存储引擎的区别是什么
两者是MySQL最常用的两种存储引擎,核心差异如下:
| 对比维度 | InnoDB | MyISAM |
|---|---|---|
| 事务支持 | 支持事务,支持外键 | 不支持事务,不支持外键 |
| 锁粒度 | 支持行级锁、表级锁 | 仅支持表级锁 |
| 索引类型 | 聚簇索引,数据和索引存储在一起 | 非聚簇索引,数据和索引分开存储 |
| 适用场景 | 写操作多、需要事务支持的场景 | 读操作多、不需要事务的场景 |
2. 什么是聚簇索引和非聚簇索引
聚簇索引的叶子节点存储的是整行数据,InnoDB的主键索引就是聚簇索引,一张表只能有一个聚簇索引。非聚簇索引的叶子节点存储的是主键值,需要通过主键值回表查询整行数据,InnoDB的二级索引都是非聚簇索引。
五、锁机制相关常见问题
1. MySQL有哪些常见的锁类型
- 按锁粒度分:表级锁、行级锁、页级锁,InnoDB默认支持行级锁
- 按锁性质分:共享锁(读锁,多个事务可以同时持有)、排他锁(写锁,只有一个事务可以持有)
- 按锁算法分:记录锁(锁单条记录)、间隙锁(锁两个记录之间的间隙)、临键锁(记录锁+间隙锁,InnoDB默认的行锁算法)
2. 什么是死锁,如何避免死锁
死锁是指两个或多个事务互相持有对方需要的锁,并且都在等待对方释放锁,导致所有事务都无法继续执行的情况。避免死锁的方法包括:
- 尽量让事务按照相同的顺序获取锁
- 尽量缩小事务的范围,减少锁的持有时间
- 为查询添加合理的索引,避免锁住过多的行
- 设置合理的锁等待超时时间,超时后自动回滚事务
以下是模拟死锁的代码示例:
-- 事务A START TRANSACTION; -- 锁定id=1的记录 UPDATE account SET balance = balance - 100 WHERE id = 1; -- 此时事务B锁定了id=2的记录,事务A等待 UPDATE account SET balance = balance + 100 WHERE id = 2; -- 事务B START TRANSACTION; -- 锁定id=2的记录 UPDATE account SET balance = balance - 100 WHERE id = 2; -- 此时事务A锁定了id=1的记录,事务B等待,形成死锁 UPDATE account SET balance = balance + 100 WHERE id = 1;