RSS
菜单
全部文章快讯开发科技深度热点

第 37 章 高频原理简答真题精讲

内容摘要

原理简答题是面试的"地基题"——答得出来不一定加分,答不上直接出局。本篇精选 20 道最高频原理题,覆盖 B+ 树、聚簇索引、MVCC、ACID、三种日志、隔离级别、锁、Buffer Pool、最左前缀、两阶段提交等。每题给要点化答案和追问应对。前置知识:第 1、3、6、7 章;本系列示例基于 MySQL 8.0。

📖 本篇简介:原理简答题是面试的"地基题"——答得出来不一定加分,答不上直接出局。本篇精选 20 道最高频原理题,覆盖 B+ 树、聚簇索引、MVCC、ACID、三种日志、隔离级别、锁、Buffer Pool、最左前缀、两阶段提交等。每题给要点化答案和追问应对。前置知识:第 1、3、6、7 章;本系列示例基于 MySQL 8.0。

目录

  • 1 本篇考情与答题原则
  • 题目 1:为什么索引用B+树
  • 题目 2:聚簇索引和非聚簇索引区别
  • 题目 3:MVCC怎么实现
  • 题目 4:事务ACID分别靠什么保证
  • 题目 5:redo undo binlog区别
  • 题目 6:事务隔离级别解决什么问题
  • 题目 7:间隙锁解决什么问题
  • 题目 8:索引为什么能加速查询
  • 题目 9:什么是覆盖索引
  • 题目 10:什么是回表
  • 题目 11:MySQL有哪些锁
  • 题目 12:主从复制原理
  • 题目 13:为什么推荐自增主键
  • 题目 14:脏读不可重复读幻读区别
  • 题目 15:Buffer Pool的作用
  • 题目 16:最左前缀原则
  • 题目 17:redo log的作用
  • 题目 18:为什么范围查询不用哈希索引
  • 题目 19:两阶段提交是什么
  • 题目 20:为什么慢查询要建合适索引
  • 速查速记
  • 常见坑与注意事项
  • 复习清单
  • 练习题

1 本篇考情与答题原则

原理简答考的是"能不能用自己的话讲清机制"。答题原则:先说结论,再讲机制,最后举个例子。别只背名词。

| 答题层次 | 示例 |

|---|---|

| 结论 | "MVCC 让读写不阻塞" |

| 机制 | "靠 undo 版本链 + ReadView 判断可见性" |

| 例子 | "RR 下事务第一次 SELECT 生成 ReadView,之后复用" |

题目 1:为什么索引用B+树

考点

  • 矮胖;叶子链表;磁盘 IO。

参考答案

1. B+ 树矮胖:非叶子不存数据,扇出大,3~4 层存千万行,树高低 = IO 少;

2. 叶子双向链表:范围查询顺链表扫,快;

3. 所有查询到叶子:路径稳定;

4. 按页读写:一页 16KB,一次带很多索引项;

5. 对比:B 树非叶子存数据树高,哈希不支持范围。

-- 索引结构对比,本示例基于 MySQL 8.0
B+树 : 非叶子不存数据, 扇出大, 3~4层存千万行, 叶子链表适合范围
B树  : 非叶子也存数据, 扇出小, 树更高
哈希 : 只支持等值, 不支持范围/排序

追问

  • 问:树高大概多少?答:千万行 3~4 层,3~4 次磁盘 IO。
  • 问:哈希索引不好吗?答:只等值,不范围。

题目 2:聚簇索引和非聚簇索引区别

考点

  • 叶子节点内容;回表。

参考答案

1. 聚簇索引(主键):叶子存整行数据,一表一个;

2. 二级(非聚簇)索引:叶子存主键值;

3. 回表:二级索引查到主键再回聚簇索引取行;

4. 覆盖索引:查询列在二级索引里免回表;

5. 没主键:InnoDB 选唯一非空索引,否则生成隐藏。

追问

  • 问:回表代价?答:多一次 B+ 树查找 + 随机 IO。
  • 问:InnoDB 和 MyISAM 索引区别?答:MyISAM 都是非聚簇,叶子存地址。

题目 3:MVCC怎么实现

考点

  • undo 链;ReadView。

参考答案

1. 隐藏列:trx_id、roll_pointer;

2. undo 版本链:旧版本串成链;

3. ReadView:活跃事务列表判断可见性;

4. RC/RR:ReadView 生成时机不同;

5. 效果:快照读不加锁,读写不阻塞。

追问

  • 问:怎么判断可见?答:版本 trx_id 在 ReadView 中,按规则比较。
  • 问:当前读呢?答:读最新,靠锁。

题目 4:事务ACID分别靠什么保证

考点

  • 各特性机制。

参考答案

1. A 原子性:undo log 回滚;

2. C 一致性:由 AID + 业务约束达成;

3. I 隔离性:锁 + MVCC;

4. D 持久性:redo log WAL;

5. 两阶段提交协调 redo/binlog。

追问

  • 问:一致性是手段还是目的?答:目的,其他三性为它服务。
  • 问:持久性靠什么刷盘?答:redo 先刷,crash 重放。

题目 5:redo undo binlog区别

考点

  • 三种日志职责。

参考答案

1. redo:InnoDB 物理日志,crash-safe;

2. undo:InnoDB 逻辑日志,回滚 + MVCC;

3. binlog:Server 层逻辑日志,复制 + 恢复;

4. redo 循环写,binlog 追加写;

5. 两阶段提交保证二者一致。

-- 三种日志职责对比,本示例基于 MySQL 8.0
redo  : InnoDB物理日志, 记录页修改, 保证crash-safe
undo  : InnoDB逻辑日志, 记录反向操作, 用于回滚+MVCC
binlog: Server层逻辑日志, 记录全部变更, 用于主从复制

追问

  • 问:为什么有 redo 还要 binlog?答:redo 管 crash 恢复,binlog 管复制和点恢复。
  • 问:redo 记录什么?答:某页某偏移改了什么。

题目 6:事务隔离级别解决什么问题

考点

  • 四种级别;并发问题。

参考答案

1. 读未提交:啥都不防;

2. 读提交 RC:防脏读;

3. 可重复读 RR:防脏读、不可重复读(InnoDB 还防幻读);

4. 串行化:全防但性能差;

5. 默认 RR:MySQL InnoDB 默认 RR。

追问

  • 问:互联网常用哪个?答:RC,并发更高、锁更少。
  • 问:RR 一定不幻读?答:快照读防,当前读靠临键锁。

题目 7:间隙锁解决什么问题

考点

  • 幻读;锁范围。

参考答案

1. 间隙锁:锁索引记录之间的间隙,防别的事务插入;

2. 解决 RR 下的幻读:当前读时别让新行插入;

3. 临键锁:记录锁 + 间隙锁;

4. 只在 RR 出现:RC 无间隙锁;

5. 代价:锁范围大,并发下降。

追问

  • 问:什么时候退化为记录锁?答:唯一索引等值命中唯一记录。
  • 问:间隙锁什么时候加?答:RR 范围查询/当前读。

题目 8:索引为什么能加速查询

考点

  • 减少扫描行数;有序定位。

参考答案

1. 没有索引:全表扫描逐行比对;

2. 有索引:B+ 树按 key 定位,从 O(n) 降到 O(log n);

3. 有序:范围查询、排序可利用索引顺序;

4. 覆盖索引:免回表更快;

5. 代价:占空间、拖慢写入。

追问

  • 问:索引越多越好?答:不是,写放大、优化器选索引成本高。
  • 问:什么列该建索引?答:高频 where/join/order by、高选择性列。

题目 9:什么是覆盖索引

考点

  • 免回表;Extra 显示。

参考答案

1. 定义:查询要的列都在索引里,不必回表;

2. EXPLAIN Extra:Using index;

3. 好处:少回表随机 IO;

4. 设计:把高频查询列加进联合索引;

5. 代价:索引变宽。

追问

  • 问:怎么看有没有覆盖?答:Extra 出现 Using index。
  • 问:覆盖索引能含大字段?答:宽索引占空间,权衡。

题目 10:什么是回表

考点

  • 二级索引 + 主键取行。

参考答案

1. 过程:二级索引查到主键 → 再到聚簇索引取整行;

2. 代价:多一次 B+ 树查找 + 随机 IO;

3. 避免:覆盖索引;

4. 触发:查询列不全在二级索引;

5. 深分页 + 回表:慢查询常见原因。

追问

  • 问:怎么减少回表?答:覆盖索引、延迟关联。
  • 问:主键查询回表吗?答:聚簇索引本身就是行,不回表。

题目 11:MySQL有哪些锁

考点

  • 粒度;算法。

参考答案

1. 按粒度:表锁、行锁;

2. 行锁算法:记录锁、间隙锁、临键锁;

3. 按性质:共享锁 S、排他锁 X;

4. 意向锁:表级,快速判断表内行锁;

5. MDL:元数据锁,DDL/DML 互斥。

追问

  • 问:什么时候加表锁?答:DDL、lock tables、全表更新。
  • 问:意向锁干嘛?答:DML 前先加意向锁,DDL 快速判断表能否锁。

题目 12:主从复制原理

考点

  • 三线程;binlog。

参考答案

1. 主库写 binlog;

2. 从库 IO 线程拉 binlog 写 relay log;

3. SQL 线程重放;

4. 格式:STATEMENT/ROW/MIXED,常用 ROW;

5. 8.0 并行复制降低延迟。

追问

  • 问:主从延迟原因?答:单线程重放、大事务、从库性能。
  • 问:半同步?答:主库等从库 ACK。

题目 13:为什么推荐自增主键

考点

  • 顺序写;页分裂;体积。

参考答案

1. 顺序插入尾部:不页分裂;

2. BIGINT 短:二级索引存主键更省空间;

3. 随机 UUID:页分裂 + 碎片;

4. 聚簇索引顺序写性能高;

5. 分库后:趋势递增分布式 ID。

追问

  • 问:UUID 真的不能用?答:可做业务展示,别当聚簇主键。
  • 问:自增主键热点?答:8.0 已优化为轻量 mutex。

题目 14:脏读不可重复读幻读区别

考点

  • 三种并发异常。

参考答案

1. 脏读:读到别的事务未提交的数据;

2. 不可重复读:同一事务两次读同一行,别人提交后变了(侧重改);

3. 幻读:同一事务两次范围查询,别人插入了新行(侧重增);

4. RC 防脏读;RR 防不可重复读;串行化全防;

5. InnoDB RR:MVCC 防幻读快照,临键锁防当前读幻读。

追问

  • 问:不可重复读和幻读区别?答:前者针对同一行被改,后者针对范围多出新行。
  • 问:怎么防幻读?答:临键锁锁住间隙。

题目 15:Buffer Pool的作用

考点

  • 内存缓存;脏页。

参考答案

1. 作用:缓存数据页/索引页,避免每次读磁盘;

2. 写先改内存页(脏页),后台刷盘;

3. 改良 LRU:young/old 两段防全表扫污染;

4. 大小:物理内存 50%~70%;

5. 命中率:高 = 性能好。

追问

  • 问:脏页什么时候刷?答:checkpoint、redo 快满、脏页比例高。
  • 问:刷脏为什么卡?答:同步刷盘占 IO。

题目 16:最左前缀原则

考点

  • 联合索引顺序;跳过前导列。

参考答案

1. 联合索引 (a,b,c):查询从最左列开始匹配;

2. 跳过 a 直接查 b:用不上索引;

3. 范围后失效:a=1 AND b>2 AND c=3——c 用不上;

4. 等值可重排:优化器能调换等值条件顺序;

5. 设计:等值列在前,范围列在后。

-- 联合索引(a,b,c)的命中情况,本示例基于 MySQL 8.0
WHERE a=1 AND b=2 AND c=3   -- 全用到
WHERE a=1 AND c=3           -- 只用到a(跳过b)
WHERE a=1 AND b>2 AND c=3   -- 用到a,b;c排在范围后只能ICP过滤
WHERE b=2                   -- 用不到(跳过前导列a)

追问

  • 问:a>1 AND b=2 哪个先?答:范围 a 在前,b 也用不上(范围后失序)。
  • 问:怎么验证?答:EXPLAIN 看 key_len 和 type。

题目 17:redo log的作用

考点

  • WAL;持久性;crash 恢复。

参考答案

1. 先写 redo 再写数据页(WAL):crash 后重放;

2. 保证持久性:已提交事务不丢;

3. 循环写:固定大小,checkpoint 推进;

4. 崩溃恢复:重启重放 redo;

5. 双 1:innodb_flush_log_at_trx_commit=1 最安全。

追问

  • 问:redo 和 binlog 谁先?答:两阶段,redo prepare 先于 binlog。
  • 问:redo 太大?答:恢复慢;太小频繁刷。

题目 18:为什么范围查询不用哈希索引

考点

  • 哈希无序。

参考答案

1. 哈希索引:哈希后无序,只支持等值;

2. 范围查询:>、<、BETWEEN 无法用哈希定位;

3. 排序/前缀:哈希不支持;

4. B+ 树:叶子有序链表,天然范围;

5. 自适应哈希:InnoDB 内部自动给热点等值建哈希。

追问

  • 问:Memory 引擎哈希索引?答:内存表支持,但 InnoDB 默认 B+ 树。
  • 问:等值查询哈希不是快?答:但数据库要范围/排序,B+ 通用。

题目 19:两阶段提交是什么

考点

  • redo 与 binlog 一致;崩溃恢复。

参考答案

1. prepare:写 redo 置 prepare;

2. commit:写 binlog,redo 置 commit;

3. 崩溃恢复:扫描 redo,prepare 看 binlog 完整与否决定提交/回滚;

4. 目的:redo 与 binlog 一致,主从不脱节;

5. 否则:主库提交了但 binlog 没写,从库少数据。

-- 两阶段提交时序,本示例基于 MySQL 8.0
阶段1 prepare: 写 redo log 并置 prepare
阶段2 commit : 写 binlog, 再把 redo 置 commit
崩溃恢复: 扫描redo, prepare态看binlog是否完整决定提交/回滚

追问

  • 问:为什么必须两阶段?答:给"提交"一个跨日志的一致判定点。
  • 问:prepare 后崩溃?答:binlog 完整就提交,否则回滚。

题目 20:为什么慢查询要建合适索引

考点

  • 全表扫描代价;索引选择性。

参考答案

1. 无索引全表扫:逐行比对,CPU/IO 高;

2. 合适索引:定位扫描行数骤降;

3. 不是建了就有用:写法失效、选择性差会白建;

4. 覆盖索引:连回表都省;

5. EXPLAIN:建完验证 type/rows。

追问

  • 问:索引建错列?答:优化器不选,等于没建。
  • 问:加索引要注意?答:写放大,控制数量。

速查速记

| 原理 | 一句话 | 关键词 |

|---|---|---|

| B+树 | 矮胖+叶子链 | 3~4层 |

| MVCC | undo链+ReadView | 读写不阻塞 |

| A/D/I | undo/redo/锁+MVCC | 三性分工 |

| 三日志 | 物理/逻辑/复制 | 两阶段 |

| 隔离级别 | RC防脏RR防重复 | 默认RR |

| 间隙锁 | RR锁间隙防幻读 | RC没有 |

| 覆盖索引 | 免回表 | Using index |

| 最左前缀 | 从左列开始 | 范围后失效 |

常见坑与注意事项

  • 坑 1:把不可重复读和幻读混为一谈——前者是同行被改,后者是范围多出新行;
  • 坑 2:以为 RC 有间隙锁——RC 只有记录锁,并发更高;
  • 坑 3:说覆盖索引就是主键索引——覆盖是"查询列都在索引里",可指任何二级索引;
  • 坑 4:以为索引建了就一定生效——写法失效、选择性差,优化器会放弃;
  • 坑 5:说 InnoDB count(*) 是 O(1)——那是 MyISAM,InnoDB 要数可见行;
  • 注意:本题库为通用原理,按 MySQL 8.0 讲解。

复习清单

| 题目 | 核心 | 易错点 |

|---|---|---|

| B+树 | 矮胖+链表 | 别和B树混 |

| MVCC | undo链+ReadView | RC/RR时机 |

| ACID | undo/redo/锁 | C是目的 |

| 三日志 | redo物理/binlog逻辑 | 两阶段 |

| 隔离级别 | RC/RR/串行 | RR防幻读 |

| 间隙锁 | RR当前读 | RC没有 |

| 最左前缀 | 等值在前范围在后 | 跳过前导列 |

| 两阶段 | prepare/commit | 崩溃看binlog |

练习题

练 1:用一段话讲清 MVCC 怎么实现可重复读。

<details>

<summary>参考答案</summary>

每行有 trx_id 和 roll_pointer,修改时在 undo 里留旧版本串成版本链;RR 事务在第一次 SELECT 时生成 ReadView(记录活跃事务列表),之后该事务读时沿版本链找第一个满足 ReadView 可见规则的版本,因此看不到别的事务后来提交的修改,实现可重复读。

</details>

练 2:联合索引 (a,b,c),查询 WHERE a=1 AND c=3 能用到索引吗?WHERE a=1 AND b>2 AND c=3 呢?

<details>

<summary>参考答案</summary>

a=1 AND c=3:能用到 a(最左前缀),c 用不上(跳过 b)。a=1 AND b>2 AND c=3:a、b 能定位,b 是范围列,c 排在范围之后失序,只能靠 ICP 在索引层过滤 c,但不能用 c 定位。

</details>

下一篇预告:第 38 章 高频场景设计真题精讲

— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《第 37 章 高频原理简答真题精讲》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。