MySQL教程 / 第 320 节

第32章:MySQL面试题精选

面试必备知识点汇总

32.1 基础知识

32.1.1 MySQL架构

Q1:MySQL的架构分为哪几层?

A:MySQL架构分为4层:
1. 连接层:处理客户端连接、认证
2. 服务层:SQL解析、优化、缓存
3. 引擎层:存储引擎(InnoDB、MyISAM等)
4. 存储层:数据存储在磁盘

Q2:InnoDB和MyISAM的区别?

A:主要区别:
1. 事务:InnoDB支持,MyISAM不支持
2. 锁:InnoDB行锁,MyISAM表锁
3. 外键:InnoDB支持,MyISAM不支持
4. 崩溃恢复:InnoDB支持,MyISAM不支持
5. MVCC:InnoDB支持,MyISAM不支持
6. 性能:InnoDB适合写多,MyISAM适合读多

推荐:统一使用InnoDB

32.2 索引相关

32.2.1 索引基础

Q3:什么是索引?有什么作用?

A:索引是帮助MySQL高效获取数据的数据结构。
作用:
1. 加快查询速度
2. 减少磁盘I/O
3. 加速排序和分组

缺点:
1. 占用空间
2. 降低写入性能
3. 需要维护

Q4:MySQL索引使用什么数据结构?为什么?

A:B+树

原因:
1. B+树高度低(3-4层),减少磁盘I/O
2. 叶子节点存储所有数据,范围查询效率高
3. 叶子节点有指针,支持顺序访问
4. 非叶子节点只存储索引,可以存储更多索引

为什么不用B树?
- B树非叶子节点也存储数据,树高更高

为什么不用哈希?
- 哈希不支持范围查询

为什么不用红黑树?
- 红黑树高度高,磁盘I/O多

Q5:什么是聚簇索引和非聚簇索引?

A:
聚簇索引(Clustered Index):
- 索引和数据存储在一起
- InnoDB的主键索引是聚簇索引
- 一个表只有一个聚簇索引

非聚簇索引(Secondary Index):
- 索引和数据分开存储
- 叶子节点存储主键值
- 需要回表查询

回表:通过非聚簇索引查到主键,再通过主键查数据

Q6:什么是覆盖索引?

A:查询的列都在索引中,不需要回表。

示例:
CREATE INDEX idx_name_age ON users(name, age);
SELECT name, age FROM users WHERE name = '张三';  -- 覆盖索引,不需要回表

SELECT name, age, email FROM users WHERE name = '张三';  -- 需要回表

Q7:什么是最左前缀原则?

A:复合索引从最左边开始匹配。

示例:
CREATE INDEX idx_abc ON table(a, b, c);

✅ 可以使用索引:
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3

❌ 不能使用索引:
WHERE b = 2
WHERE c = 3
WHERE b = 2 AND c = 3

32.2.2 索引失效

Q8:哪些情况会导致索引失效?

A:
1. 在索引列上使用函数
   WHERE YEAR(create_time) = 2024  ❌
   WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01'  ✅

2. 隐式类型转换
   WHERE phone = 123456789  ❌(phone是VARCHAR)
   WHERE phone = '123456789'  ✅

3. LIKE以%开头
   WHERE name LIKE '%张%'  ❌
   WHERE name LIKE '张%'  ✅

4. OR条件(其中一个列没有索引)
   WHERE name = '张三' OR age = 18  ❌(age没有索引)

5. 不等于(!=、<>)
   WHERE status != 1  ❌

6. IS NULL / IS NOT NULL(视情况)
   WHERE name IS NULL  ❌(可能失效)

7. NOT IN、NOT EXISTS
   WHERE id NOT IN (1, 2, 3)  ❌

32.3 事务相关

32.3.1 事务基础

Q9:什么是事务?ACID是什么?

A:事务是一组SQL操作,要么全部成功,要么全部失败。

ACID:
1. Atomicity(原子性):事务不可分割
2. Consistency(一致性):事务前后数据一致
3. Isolation(隔离性):事务之间互不影响
4. Durability(持久性):事务提交后永久保存

Q10:MySQL的事务隔离级别有哪些?

A:4个隔离级别(从低到高):

1. READ UNCOMMITTED(读未提交)
   - 可以读到未提交的数据
   - 问题:脏读、不可重复读、幻读

2. READ COMMITTED(读已提交)
   - 只能读到已提交的数据
   - 问题:不可重复读、幻读
   - Oracle默认

3. REPEATABLE READ(可重复读)
   - 同一事务中多次读取结果一致
   - 问题:幻读(InnoDB通过MVCC+间隙锁解决)
   - MySQL默认 ✅

4. SERIALIZABLE(串行化)
   - 最高隔离级别,完全串行执行
   - 问题:性能差

推荐:REPEATABLE READ

Q11:什么是脏读、不可重复读、幻读?

A:
脏读(Dirty Read):
- 读到其他事务未提交的数据
- 示例:事务A修改但未提交,事务B读到了修改后的数据

不可重复读(Non-Repeatable Read):
- 同一事务中多次读取结果不一致
- 示例:事务A读取两次,中间事务B修改并提交,两次结果不同

幻读(Phantom Read):
- 同一事务中多次查询,记录数不一致
- 示例:事务A查询两次,中间事务B插入新记录,第二次多了记录

Q12:什么是MVCC?

A:MVCC(Multi-Version Concurrency Control)多版本并发控制

原理:
1. 每行记录有两个隐藏列:trx_id(事务ID)、roll_pointer(回滚指针)
2. 每次修改生成新版本,旧版本通过undo log保存
3. 读取时根据事务ID判断可见性

优点:
- 读不加锁,提高并发性能
- 解决不可重复读问题

InnoDB通过MVCC+间隙锁解决幻读

32.4 锁相关

32.4.1 锁类型

Q13:MySQL有哪些锁?

A:
按粒度分:
1. 表锁:锁整个表(MyISAM)
2. 行锁:锁单行(InnoDB)
3. 间隙锁:锁范围(InnoDB)

按类型分:
1. 共享锁(S锁):读锁,多个事务可以同时持有
2. 排他锁(X锁):写锁,只有一个事务可以持有

按算法分:
1. Record Lock:记录锁
2. Gap Lock:间隙锁
3. Next-Key Lock:记录锁+间隙锁

Q14:什么是死锁?如何避免?

A:
死锁:两个或多个事务互相等待对方释放锁。

示例:
事务A:锁住行1,等待行2
事务B:锁住行2,等待行1

避免方法:
1. 按相同顺序访问资源
2. 减少锁持有时间
3. 使用乐观锁
4. 降低隔离级别
5. 设置锁等待超时:innodb_lock_wait_timeout

32.5 性能优化

32.5.1 SQL优化

Q15:如何优化慢查询?

A:
1. 分析执行计划(EXPLAIN)
2. 添加索引
3. 避免SELECT *
4. 避免索引失效
5. 优化JOIN
6. 分页优化
7. 使用覆盖索引
8. 避免子查询,改用JOIN

Q16:如何优化深分页?

A:
问题SQL:
SELECT * FROM orders ORDER BY id LIMIT 1000000, 10;

优化方案:
1. 子查询优化
SELECT * FROM orders 
WHERE id >= (SELECT id FROM orders ORDER BY id LIMIT 1000000, 1)
LIMIT 10;

2. 延迟关联
SELECT o.* FROM orders o
INNER JOIN (SELECT id FROM orders ORDER BY id LIMIT 1000000, 10) t
ON o.id = t.id;

3. 记录上次最大ID
SELECT * FROM orders WHERE id > @last_id ORDER BY id LIMIT 10;

32.5.2 参数优化

Q17:重要的MySQL参数有哪些?

A:
1. innodb_buffer_pool_size:缓冲池大小(50-70%内存)
2. innodb_log_file_size:redo log大小
3. innodb_flush_log_at_trx_commit:刷盘策略(1:最安全,2:性能好)
4. sync_binlog:binlog刷盘策略
5. max_connections:最大连接数
6. query_cache_size:查询缓存(MySQL 8.0已移除)

32.6 高可用

32.6.1 主从复制

Q18:MySQL主从复制原理?

A:
1. 主库写入binlog
2. 从库I/O线程读取binlog,写入relay log
3. 从库SQL线程执行relay log

三个线程:
- 主库:binlog dump线程
- 从库:I/O线程、SQL线程

Q19:主从延迟如何解决?

A:
原因:
1. 从库性能差
2. 主库写入量大
3. 大事务
4. 网络延迟

解决方案:
1. 升级从库硬件
2. 并行复制(MySQL 5.7+)
3. 拆分大事务
4. 读写分离,读从库时容忍延迟
5. 重要查询读主库

32.7 实战问题

Q20:如何设计秒杀系统?

A:
1. 数据库层面:
   - 使用乐观锁(version字段)
   - 减库存SQL:UPDATE ... WHERE stock > 0 AND version = @old_version

2. 缓存层面:
   - Redis预减库存
   - 库存放入Redis

3. 消息队列:
   - 削峰填谷
   - 异步处理订单

4. 限流:
   - 接口限流
   - 用户限流(一人一单)

32.8 本章总结

本章学习内容:

  • 基础知识(架构、存储引擎)⭐⭐⭐⭐⭐
  • 索引相关(B+树、索引失效)⭐⭐⭐⭐⭐
  • 事务相关(ACID、隔离级别、MVCC)⭐⭐⭐⭐⭐
  • 锁相关(锁类型、死锁)⭐⭐⭐⭐⭐
  • 性能优化(慢查询、参数)⭐⭐⭐⭐⭐
  • 高可用(主从复制)⭐⭐⭐⭐⭐
  • 实战问题⭐⭐⭐⭐⭐

高频面试题:

  1. InnoDB和MyISAM的区别
  2. 索引为什么用B+树
  3. 索引失效的情况
  4. 事务隔离级别
  5. MVCC原理
  6. 死锁如何避免
  7. 如何优化慢查询
  8. 主从复制原理
  9. 如何设计秒杀系统
  10. 如何优化深分页

面试技巧:

  • 先说原理,再说实践
  • 结合实际项目经验
  • 说出优缺点和适用场景
  • 准备几个实战案例

下一章预告: 疑难问题解决方案


练习题

  1. InnoDB和MyISAM有什么区别?
  2. 索引为什么用B+树?
  3. 什么是聚簇索引?
  4. 哪些情况会导致索引失效?
  5. 什么是MVCC?
  6. MySQL的事务隔离级别有哪些?
  7. 什么是死锁?如何避免?
  8. 如何优化慢查询?
  9. 主从复制原理是什么?
  10. 如何设计秒杀系统?

继续学习: 第33章:疑难问题解决方案