复习定位

MySQL 面试最常问的是 InnoDB。回答时优先把索引、事务、锁、日志和执行计划连起来,不要只背零散概念。

InnoDB 和索引

为什么常说 InnoDB 用 B+ 树?

B+ 树适合磁盘存储:

  • 非叶子节点只存键和指针,单页能放更多索引项,树高更低。
  • 叶子节点按顺序连接,范围查询方便。
  • 每次查询路径比较稳定,适合数据库页读取。

聚簇索引和二级索引

InnoDB 的主键索引是聚簇索引,叶子节点存整行数据。

二级索引的叶子节点存主键值。通过二级索引查到主键后,如果还需要其他列,就要回表到聚簇索引查整行。

优化方向:能用覆盖索引就减少回表。

最左前缀原则

联合索引按从左到右顺序生效。比如索引 (a, b, c)

  • where a = ? 可以用。
  • where a = ? and b = ? 可以用。
  • where b = ? 通常用不上这个联合索引的完整优势。
  • 遇到范围查询后,后面的列可能无法继续用于有序定位。

索引失效常见情况

常见原因:

  • 对索引列做函数或表达式计算。
  • 字符串不加引号导致隐式转换。
  • 左模糊查询,例如 like '%abc'
  • 联合索引不满足最左前缀。
  • 数据量太小或优化器判断全表更划算。

事务和隔离级别

ACID:

  • Atomicity:原子性,要么都成功,要么都失败。
  • Consistency:一致性,事务前后约束不被破坏。
  • Isolation:隔离性,并发事务之间互不干扰到指定程度。
  • Durability:持久性,提交后数据可靠保存。

隔离级别:

  • READ UNCOMMITTED:可能脏读。
  • READ COMMITTED:解决脏读,但可能不可重复读。
  • REPEATABLE READ:MySQL InnoDB 默认级别,配合 MVCC 和锁解决大量并发问题。
  • SERIALIZABLE:最严格,并发性能最低。

MVCC

MVCC 是多版本并发控制,让读写尽量不互相阻塞。

核心概念:

  • undo log 保存历史版本。
  • Read View 决定当前事务能看到哪些版本。
  • 隐藏字段记录事务 id 和回滚指针。

快照读走 MVCC,例如普通 select。当前读读取最新数据并加锁,例如 select ... for update、update、delete。

常见锁:

  • 行锁:锁记录,粒度小。
  • 表锁:锁整张表,粒度大。
  • 间隙锁:锁索引记录之间的间隙,防止幻读。
  • Next-Key Lock:记录锁 + 间隙锁。

面试重点:InnoDB 行锁是基于索引实现的。如果条件没走索引,可能退化成更大范围的锁。

日志

redo log

redo log 保证崩溃恢复。事务提交后,即使脏页还没刷到磁盘,也能通过 redo log 恢复。

undo log

undo log 用于回滚和 MVCC 历史版本读取。

binlog

binlog 是 MySQL Server 层日志,常用于主从复制和数据恢复。

常见追问:两阶段提交用于协调 redo log 和 binlog,降低崩溃时两份日志不一致的风险。

慢查询优化思路

可以按顺序排查:

  1. 看 SQL 是否只查必要列,避免 select *
  2. 用 explain 看访问类型、索引、扫描行数。
  3. 检查 where、order by、group by 是否能利用索引。
  4. 避免大偏移分页,必要时用基于游标的翻页。
  5. 控制单表数据量,必要时归档或分库分表。
  6. 结合业务缓存,但不要把所有问题都丢给缓存。

面试收束

MySQL 高频题可以用一条线串:查询为什么慢 -> 索引怎么建 -> 事务怎么隔离 -> 锁怎么影响并发 -> 日志怎么保证可靠。

参考资料

  • JavaGuide:https://javaguide.cn/
  • JavaGuide GitHub:https://github.com/Snailclimb/JavaGuide