数据库
面试权重:★★★ | 适用级别:P7/P8+ | 预计复习时间:2-3周
概览
面试权重:★★★ | 适用级别:P7/P8+ | 预计复习时间:2-3周
数据库专题的高频主线通常是"索引 -> 事务 -> 锁 -> 日志 -> SQL 优化 -> 高可用"。真正能拉开差距的,不是把名词背全,而是能解释每个机制为什么存在、它们在线上问题里如何互相影响。
建议用法
复习时建议按"查询为什么快、写入为什么安全、并发为什么不乱、出问题怎么排查"四条线去读。这比单独背 B+ 树、MVCC、redo log 更容易形成面试回答闭环。
一、知识体系
1. MySQL核心原理 ★★★
1.1 存储引擎
InnoDB 为什么是面试主角
- 核心结论
- 后端面试默认语境几乎都是 InnoDB,因为它同时覆盖事务、行锁、MVCC、Buffer Pool、崩溃恢复这些高频问题。
- MyISAM 主要作为对比对象存在,用来说明为什么今天大部分 OLTP 场景会选 InnoDB。
- 原理展开
- InnoDB 支持事务和行级锁,能更好地支撑高并发读写。
- InnoDB 采用聚簇索引,主键索引叶子节点直接存整行数据,这也解释了为什么主键设计会影响存储和二级索引大小。
- Buffer Pool 是 InnoDB 最核心的性能设施之一,热点页尽量走内存,避免每次都打磁盘。
- Change Buffer、Adaptive Hash Index、Doublewrite Buffer 这些点不要求每次都深讲,但面试里属于很好的加分项。
- 面试怎么答
- "InnoDB 真正强在事务、MVCC、行锁和崩溃恢复能力。对业务系统来说,读写并发和一致性比单纯读性能更重要,所以它成了默认选择。"
- 易错点
- 不要把 InnoDB 只答成"支持事务、支持外键"两句话,那样深度不够。
InnoDB vs MyISAM 的回答方式
- 核心结论
- 对比不要只停留在功能清单,而要落到场景选择。
- 关键对比
| 维度 | InnoDB | MyISAM |
|---|---|---|
| 事务 | 支持 | 不支持 |
| 锁粒度 | 行级锁为主 | 表级锁 |
| 索引组织 | 聚簇索引 | 非聚簇 |
| 崩溃恢复 | 支持 | 较弱 |
| 适用场景 | OLTP、高并发读写 | 早期读多写少场景 |
- 面试怎么答
- "今天业务系统几乎默认选 InnoDB。只有在极少数只读、历史兼容、无事务诉求场景里,才会谈到 MyISAM。"
1.2 索引原理 ★★★
B+树为什么适合数据库索引
- 核心结论
- B+ 树的优势不是一句"范围查询更快",而是它同时兼顾了磁盘 IO、范围访问和稳定树高。
- 原理展开
- 非叶子节点只存键不存值,单页能容纳更多 key,因此树更矮,磁盘 IO 次数更少。
- 叶子节点通过链表串起来,天然适合范围扫描、排序和分页。
- 相比 Hash 索引,B+ 树不仅能做等值查询,还能做范围查询、排序、最左前缀匹配。
- 相比红黑树,B+ 树更适合磁盘页组织,一次 IO 能覆盖更多分支。
- 面试怎么答
- "MySQL 用 B+ 树,本质是在磁盘页这个约束下做最优折中。它既把树压得足够矮,又保留了范围查询能力,这是 Hash 和红黑树都很难同时做到的。"
- 常见追问
- 为什么不是 B 树?
- 三层 B+ 树大概能放多少数据?
聚簇索引、二级索引、回表与覆盖索引
- 核心结论
- InnoDB 的主键索引是聚簇索引,二级索引叶子节点里存的是主键值,不是整行。
- "回表"与"覆盖索引"是索引优化里的最高频追问。
- 原理展开
- 用二级索引命中后,如果查询字段不全在索引里,就要再拿主键回聚簇索引读整行,这就是回表。
- 如果查询列都在索引中,就能直接返回结果,这就是覆盖索引。
- 所以联合索引设计不仅要考虑过滤能力,还要考虑是否能覆盖高频查询。
- 面试怎么答
- "二级索引能加速定位,但回不回表决定了最终成本。很多 SQL 优化的核心,其实就是让高频查询尽量走覆盖索引。"
- 易错点
- 不要把"二级索引里存的是整行数据"说错。
联合索引、最左前缀与索引失效
- 核心结论
- 联合索引的设计核心是查询模式,而不是把高频列都堆上去。
- 原理展开
- 最左前缀原则本质是 B+ 树按索引列顺序组织,必须从最左列开始才能连续利用有序性。
- 范围查询通常会截断后续列的有序利用能力。
- 索引失效常见于函数操作、表达式计算、隐式类型转换、左模糊、
OR条件不统一、选择度过低等场景。
- 面试怎么答
- "联合索引不是列越多越好,而是要围绕 where、order by、group by 的实际模式去设计。最左前缀不是死规则,它背后是索引有序组织方式。"
- 常见追问
- 范围查询后面的列还能不能用?
- 什么叫索引下推?
1.3 事务 ★★★
ACID 在 MySQL 里分别靠什么实现
- 核心结论
- 事务不是抽象口号,面试里要能落到 undo log、redo log、锁、MVCC 这些具体机制。
- 原理展开
- 原子性靠 undo log 回滚。
- 持久性靠 redo log 和 WAL 机制。
- 隔离性靠锁和 MVCC。
- 一致性更多是事务机制、约束和业务规则共同结果。
- 面试怎么答
- "ACID 里最值得深讲的是 A、I、D。因为 undo、redo、锁和 MVCC 正好是 InnoDB 的核心内部机制。"
事务隔离级别与典型并发问题
- 核心结论
- 四个隔离级别必须会,但真正拉开差距的是能说清脏读、不可重复读、幻读与 MySQL 默认 RR 的实现方式。
- 原理展开
READ UNCOMMITTED允许读到未提交数据,几乎不用。READ COMMITTED每次读生成新 ReadView,容易出现不可重复读。REPEATABLE READ在 InnoDB 中结合 MVCC 和 Next-Key Lock,既保证可重复读,也能在当前读场景下抑制幻读。SERIALIZABLE通过最强锁粒度换最强隔离,代价最大。
- 面试怎么答
- "MySQL 默认 RR,不只是因为名字好听,而是它用 MVCC 解决快照读的一致性,再用间隙锁解决当前读下的幻读风险,在性能和隔离性之间做了比较好的平衡。"
- 易错点
- 不能机械地说"RR 一定完全没有幻读",要区分快照读和当前读。
MVCC:版本链、undo log、ReadView
- 核心结论
- MVCC 的核心是"让读尽量不阻塞写",而不是简单地"多版本"三个字。
- 原理展开
- InnoDB 会在记录上维护隐藏列,如事务 ID、回滚指针等。
- 更新时旧版本会写入 undo log,形成版本链。
- 一致性读时根据 ReadView 判断哪些事务可见、哪些版本可读。
- RC 和 RR 的最大区别之一,是 ReadView 的生成时机不同。
- 面试怎么答
- "MVCC 的本质是版本链 + ReadView。读请求不必总去抢锁,而是按可见性规则读合适版本,这就是高并发下读写能共存的关键。"
- 常见追问
- RC 和 RR 的 ReadView 区别?
- 快照读和当前读分别是什么?
1.4 锁机制 ★★★
行锁、间隙锁、临键锁
- 核心结论
- 讲锁不要只分表锁和行锁,真正高频是 Next-Key Lock 如何抑制幻读。
- 原理展开
- Record Lock 锁具体记录。
- Gap Lock 锁记录间隙,防止插入。
- Next-Key Lock 是记录锁 + 间隙锁,默认是 InnoDB 在 RR 下处理当前读的重要手段。
- 意向锁不是给业务显式加的,而是引擎为实现多粒度锁协调自动维护的。
- 面试怎么答
- "InnoDB 的并发控制重点不在'有没有行锁',而在它如何通过行锁、间隙锁、临键锁控制可见性与插入竞争。"
- 易错点
- Gap Lock 锁的是区间,不是已有记录本身。
死锁的形成与治理
- 核心结论
- 死锁不可完全避免,但可以通过访问顺序、索引设计和事务粒度控制显著降低概率。
- 原理展开
- 两个事务交叉持有对方需要的锁时就会死锁。
- 没有命中索引时,扫描范围扩大,锁粒度也会实际放大,死锁概率会明显提升。
- InnoDB 会主动检测死锁并回滚代价较小的一方。
- 面试怎么答
- "死锁治理的关键不是背定义,而是减少大事务、固定访问顺序、让更新尽量走索引、避免无序批量操作。"
1.5 日志系统 ★★★
redo log、undo log、binlog 的职责边界
- 核心结论
- 三类日志的价值要放到"事务恢复、MVCC、主从复制"三条主线里回答。
- 原理展开
- redo log 是 InnoDB 引擎层的物理日志,用于崩溃恢复。
- undo log 用于事务回滚和 MVCC 历史版本维护。
- binlog 是 Server 层逻辑日志,用于主从复制和归档审计。
- redo 是循环写,binlog 是追加写,这也是两者管理方式不同的根本原因。
- 面试怎么答
- "redo 解决崩溃恢复,undo 解决回滚和 MVCC,binlog 解决复制和归档。三者不是重复造轮子,而是分别服务不同层次的问题。"
两阶段提交为什么重要
- 核心结论
- 两阶段提交是为了保证引擎层 redo log 和 server 层 binlog 的一致性,不是为了炫技。
- 原理展开
- 如果 redo 已提交但 binlog 没写成功,主库恢复后数据存在,但从库拿不到这次变更。
- 如果 binlog 写了但 redo 没提交成功,主库崩溃恢复后可能没有这笔数据,但从库却会同步到。
- 所以 InnoDB 通过 prepare -> 写 binlog -> commit 的方式把两者绑定起来。
- 面试怎么答
- "两阶段提交解决的是主从复制场景下的日志一致性。如果只会说 prepare 和 commit,但说不清不一致后果,回答就还不够扎实。"
2. SQL优化 ★★★
2.1 执行计划(EXPLAIN) ★★★
- 核心结论
EXPLAIN不是面试背诵表,而是把 SQL 优化从猜测变成证据链的入口。
- 重点关注
type:访问类型,ALL通常意味着全表扫描。key:真正使用的索引。rows:预估扫描行数。Extra:Using index、Using filesort、Using temporary等高频信号。
- 面试怎么答
- "我看执行计划会先看有没有走对索引,再看扫描行数和额外代价,比如 filesort、temporary,最后再结合业务数据分布判断预估是否靠谱。"
2.2 慢SQL优化步骤
- 标准链路
- 先拿到慢 SQL 样本,不靠猜。
- 用
EXPLAIN看执行计划。 - 判断是索引设计问题、SQL 写法问题,还是数据量和架构问题。
- 再决定是否需要改索引、改 SQL、拆分查询、引入缓存或分库分表。
- 易错点
- 还没确认瓶颈就先加索引,容易把写性能和存储成本一起拖垮。
2.3 常见优化技巧
- 深分页
- 核心思路是避免偏移量过大带来的扫描浪费,可用延迟关联、子查询主键回表、游标分页。
COUNT(*)- InnoDB 下
COUNT(*)、COUNT(1)在多数场景差异很小,重点是是否能用上更小的索引和是否必须全表统计。
- InnoDB 下
INvsEXISTS- 要结合驱动表大小和执行计划,不要背机械结论。
ORDER BY/GROUP BY- 能用索引解决就别交给 filesort 和临时表。
3. 高可用架构 ★★
3.1 主从复制 ★★★
主从复制链路与延迟来源
- 核心结论
- 主从复制本质是主库写 binlog,从库拉取并重放;问题主要出在传输和执行速度不一致。
- 原理展开
- 主库写 binlog,从库 I/O 线程拉到 relay log,再由 SQL 线程回放。
- 大事务、DDL、从库硬件差、单线程回放、热点更新都可能导致复制延迟。
- 面试怎么答
- "主从延迟不是一个单点问题,既可能卡在拉日志,也可能卡在回放执行。治理时要先判断瓶颈在哪一段。"
- 追问提醒
- 半同步复制、并行复制、GTID、读写一致性兜底
3.2 读写分离
- 核心结论
- 读写分离提升读能力很有效,但一定会带来短暂一致性问题。
- 原理展开
- 刚写完就去从库读,可能读到旧值,这是读写分离最典型的业务坑。
- 常见解法包括写后读走主库、短时间强制主库路由、关键链路引入一致性标记等。
- 面试怎么答
- "读写分离不只是中间件配置题,核心是业务能否接受复制延迟,以及你怎么给关键链路做一致性兜底。"
3.3 分库分表 ★★★
什么时候该分,分了会带来什么代价
- 核心结论
- 分库分表是容量手段,不是性能万金油。单库单表还能撑住时,优先做 SQL 和索引治理通常更划算。
- 原理展开
- 垂直拆分解决业务边界和资源隔离,水平拆分解决单表数据量和并发写压力。
- 分片键选择要兼顾数据均匀、查询路由和扩容便利。
- 代价包括跨片查询、排序聚合、事务复杂化、扩容迁移和运维成本上升。
- 面试怎么答
- "分库分表通常是最后手段之一。我要先确认瓶颈是不是已经到了单机边界,再决定是垂直拆业务,还是水平拆热点表。"
- 易错点
- 不能只讲分法,不讲扩容和迁移。
4. NoSQL ★★
4.1 Redis(见中间件篇)
- 一句话结论
- Redis 更多承担热点读、缓存、计数和轻量结构化数据能力,不替代关系型事务数据库。
4.2 MongoDB
- 一句话结论
- 文档模型适合结构弹性大、对象层级深、聚合查询相对灵活的业务。
- 补充说明
- 典型落点包括日志、内容、配置、IoT 等弱事务或文档化场景。
4.3 Elasticsearch(见中间件篇)
- 一句话结论
- ES 更像搜索和分析引擎,不应该被当成主交易库。
4.4 数据库选型思维
- 核心结论
- 选型不能只看技术流行度,要回到业务读写模式、一致性要求、查询模型和团队驾驭能力。
- 简化框架
- 强事务、复杂关联查询:优先关系型数据库。
- 文档结构灵活:考虑 MongoDB。
- 搜索和聚合分析:考虑 Elasticsearch。
- 高并发缓存和计数:Redis 更合适。
二、高频面试题
基础级(P7必答)
- MySQL 索引为什么用 B+树?和 B 树、Hash 的区别?
- 30秒答法:B+ 树非叶子节点只存键,树更矮,单次 IO 能覆盖更多范围;叶子节点链表又支持范围查询和排序。Hash 适合等值查找但不擅长范围扫描,B 树非叶子也存数据,页利用率不如 B+ 树稳定。
- 关键词:磁盘 IO、树高、叶子链表、范围查询、Hash
- 追问提醒:为什么数据库索引不选红黑树;三层 B+ 树容量估算
- 什么是回表?什么是覆盖索引?怎么优化?
- 30秒答法:二级索引叶子节点存的是主键值,命中后如果查询列不全在索引里,就还得回聚簇索引拿整行,这就是回表。覆盖索引则可以直接从索引返回结果,通常更快。
- 关键词:二级索引、聚簇索引、回表、覆盖索引
- 追问提醒:联合索引怎么设计才能减少回表;
select *为什么危险
- 事务隔离级别有哪些?MySQL 默认哪个?RR 怎么解决幻读?
- 30秒答法:隔离级别有 RU、RC、RR、Serializable。MySQL InnoDB 默认 RR,通过 MVCC 保证快照读一致性,再通过 Next-Key Lock 处理当前读下的幻读风险。
- 关键词:RC、RR、MVCC、Next-Key Lock、幻读
- 追问提醒:ReadView 的创建时机;快照读和当前读区别
- MVCC 的实现原理是什么?
- 30秒答法:MVCC 依赖隐藏列、undo log 形成的版本链,以及 ReadView 的可见性判断。读请求根据快照选历史版本,尽量不和写请求互相阻塞。
- 关键词:undo log、版本链、ReadView、快照读
- 追问提醒:RC 和 RR 的差别;为什么 MVCC 不能完全替代锁
- redo log 和 binlog 有什么区别?为什么需要两阶段提交?
- 30秒答法:redo log 是 InnoDB 的物理日志,用于崩溃恢复;binlog 是 Server 层逻辑日志,用于复制和归档。两阶段提交是为了让两者在崩溃场景下保持一致,避免主从数据错位。
- 关键词:redo、binlog、崩溃恢复、主从复制、两阶段提交
- 追问提醒:redo 为什么循环写;binlog 三种格式怎么选
- 怎么系统化排查慢 SQL?
- 30秒答法:先拿到慢 SQL 样本,再看
EXPLAIN是否走对索引、扫描行数是否异常、有没有filesort或temporary,然后判断是索引设计、SQL 写法还是数据规模问题,最后再决定优化手段。 - 关键词:慢查询日志、EXPLAIN、扫描行数、索引设计
- 追问提醒:深分页、排序、聚合分别怎么优化
- 联合索引最左前缀原则是什么?哪些情况容易失效?
- 30秒答法:联合索引按列顺序组织,必须从最左列开始连续利用。函数操作、表达式、隐式类型转换、左模糊、范围查询截断等都可能让索引利用率变差甚至失效。
- 关键词:联合索引、最左前缀、隐式转换、左模糊
- 追问提醒:索引下推;范围查询后续列能否继续用
- 死锁是怎么产生的?怎么排查和避免?
- 30秒答法:两个事务交叉等待对方持有的锁就会死锁。排查通常看
SHOW ENGINE INNODB STATUS;治理主要靠固定访问顺序、缩短事务、让更新命中索引、减少无序批量操作。 - 关键词:死锁、锁等待、事务顺序、索引命中
- 追问提醒:InnoDB 怎么选回滚哪一个;大事务为何更容易死锁
- 主从复制延迟怎么解决?
- 30秒答法:先判断延迟出在拉日志还是重放执行,再针对性做并行复制、缩小事务、提升从库能力,或者在业务层对关键读强制走主库。
- 关键词:binlog、relay log、并行复制、强制主库
- 追问提醒:半同步复制;GTID;读写分离一致性策略
- 分库分表什么时候做?分片键怎么选?
- 30秒答法:当单机容量、单表规模、并发写入已经明显接近边界时再考虑分库分表。分片键要兼顾数据均匀、核心查询路由能力和未来扩容便利,不能只看散列是否平均。
- 关键词:容量瓶颈、分片键、数据倾斜、扩容迁移
- 追问提醒:跨片查询怎么处理;全局 ID 怎么设计
进阶级(P8+深挖)
- Buffer Pool 的 LRU 为什么要分 young/old 区?
- 30秒答法:这是为了避免一次性扫描把真正热点页冲掉。新读入页先放 old 区,只有停留足够久或再次访问才晋升到 young 区,从而减少全表扫描等冷数据污染缓存。
- 关键词:Buffer Pool、young/old、缓存污染、全表扫描
- 追问提醒:脏页刷盘;checkpoint;冷热页管理
- binlog 三种格式怎么选?
- 30秒答法:Statement 日志小但容易有非确定性问题,Row 最可靠但量更大,Mixed 是折中。生产里如果更看重一致性,通常会优先 Row。
- 关键词:Statement、Row、Mixed、一致性、日志量
- 追问提醒:
binlog_row_image;主从复制场景
- 分库分表后全局唯一 ID 通常怎么做?
- 30秒答法:常见方案有号段模式和 Snowflake。前者更稳、便于治理,后者性能高、趋势有序,但要处理时钟回拨和机器号分配问题。
- 关键词:号段、Snowflake、时钟回拨、机器号
- 追问提醒:Leaf、Tinyid;数据库号段双 buffer
- 半同步复制和异步复制怎么权衡?
- 30秒答法:异步复制性能更好但主库成功返回后仍可能丢最近变更,半同步会多等一个从库确认,牺牲一点延迟换更强的数据安全性。
- 关键词:异步复制、半同步、RTT、数据安全
- 追问提醒:after_sync 和 after_commit;对业务 RT 的影响
- 你做过哪些 SQL 优化?怎么证明效果?
- 30秒答法:回答时要给出问题 SQL、执行计划、优化动作和量化结果,比如从全表扫描改成联合索引覆盖查询,RT 从 800ms 降到 20ms,扫描行数从百万降到千级。
- 关键词:执行计划、扫描行数、RT、量化结果
- 追问提醒:是否影响写入性能;如何灰度验证
三、实战场景题(P8+重点)
- 接手服务后发现慢 SQL 很多,如何系统治理?
- 回答框架
- 先做画像:慢查询日志、TOP SQL、影响面。
- 再分类:索引缺失、SQL 写法差、数据模型不合理、架构容量不足。
- 再治理:索引优化、SQL 改写、缓存前置、读写分离、分库分表。
- 最后建立机制:上线 SQL 审查、指标监控、回归验证。
- 核心关注点:不是修一条 SQL,而是建立可持续治理机制。
- 订单表到了数亿级,如何设计分库分表方案?
- 回答框架
- 先确认核心查询模式和业务约束。
- 再选分片键,通常优先围绕订单主查询路径。
- 再设计路由、全局 ID、扩容方案和历史数据迁移。
- 最后评估跨片查询、事务、归档和运维成本。
- 核心关注点:分法、迁移、扩容三件事必须一起回答。
- 读写分离后用户刚写完读不到,怎么处理?
- 回答框架
- 先解释原因:主从复制延迟。
- 再给策略:写后读走主库、会话级主库粘连、一致性标记、关键链路短时间强制主库。
- 最后说明权衡:一致性更强意味着主库读压力更大。
- 核心关注点:这不是数据库 bug,而是架构 trade-off。
- 线上要给大表加字段,如何尽量不影响业务?
- 回答框架
- 先确认 MySQL 版本和 DDL 类型。
- 能在线 DDL 就优先在线,必要时使用
pt-online-schema-change或gh-ost。 - 做灰度、压测、低峰执行和回滚预案。
- 核心关注点:大表 DDL 重点是风险控制,不是命令本身。
四、学习资源推荐
书籍
- 《高性能MySQL》:数据库优化与架构主线必读
- 《MySQL技术内幕:InnoDB存储引擎》:适合深挖 InnoDB 机制
- 《MySQL是怎样运行的》:偏通俗,适合建立底层框架
博客/文章
- 丁奇《MySQL 45讲》:适合把原理和案例连起来
- 美团技术团队数据库相关文章:偏工程实践
- ShardingSphere 官方文档:分库分表和读写分离实战参考
视频
- MySQL 执行计划与慢 SQL 优化实战课程
- 分库分表与主从复制实战分享