04-数据库篇面试题
对应原始资料:
12-BAT/03-数据库篇
一、索引
Q1:为什么 InnoDB 用 B+ 树
- 比 B 树矮(非叶子不存数据),磁盘 IO 少。
- 叶子有序链表,范围查询快。
- 比哈希支持范围、排序、最左前缀。
Q2:聚簇索引 vs 二级索引
- 聚簇索引:叶子节点存整行数据,主键即聚簇索引(一张表只有一个)。
- 二级索引(非聚簇):叶子存主键值,查询需要回表到聚簇索引。
Q3:覆盖索引
查询的列都在索引中,不需要回表,Using index。
Q4:联合索引与最左前缀
(a, b, c) 生效:a / a,b / a,b,c。
- 范围查询右侧失效(
a > 1 and b = 2的 b 用不上索引)。
Q5:索引失效场景
- 函数/运算:
WHERE salary * 2 > 1。 - 隐式转换:phone varchar,传数字。
LIKE '%abc'左侧 %。- OR 一侧无索引。
- 不符合最左前缀。
- 数据分布(优化器选全表)。
Q6:explain 关注什么
type:至少range/ref,避免ALL。key/possible_keys。rows:扫描行数。Extra:Using index(覆盖)、Using filesort、Using temporary。
Q7:索引下推 ICP(5.6+)
联合索引中,存储引擎层先用索引列过滤,减少回表。
二、事务
Q8:ACID
原子、一致、隔离、持久。
Q9:并发问题
脏读、不可重复读、幻读。
Q10:四种隔离级别
| 级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | √ | √ | √ |
| 读已提交(RC) | × | √ | √ |
| 可重复读(RR,MySQL 默认) | × | × | √(MVCC 解决) |
| 串行化 | × | × | × |
Q11:MVCC 原理
多版本并发控制,每行有隐藏字段(事务 ID、回滚指针),undo log 版本链 + read view 决定看到哪个版本。
- RC:每次 SELECT 生成新 read view。
- RR:事务第一次 SELECT 生成 read view 并复用。
Q12:MySQL 如何解决幻读
RR 级别用 MVCC(快照读)+ 间隙锁/临键锁(当前读 SELECT ... FOR UPDATE)。
三、锁
Q13:行锁、表锁、间隙锁
- 行锁:锁单行(共享 S、排他 X)。
- 间隙锁:锁区间,防止插入。
- 临键锁 Next-Key Lock:行锁 + 间隙锁(RR 默认)。
- 意向锁:表级,意向 IS/IX。
Q14:共享锁 vs 排他锁
- S(
LOCK IN SHARE MODE):可读不可写。 - X(
FOR UPDATE):读写都锁。
Q15:死锁
两个事务互相等待对方释放锁。
- 检测:
innodb_deadlock_detect默认开启。 SHOW ENGINE INNODB STATUS看死锁日志。
四、SQL 优化
Q16:大表分页优化
LIMIT 1000000, 10 慢。 方案:
- 用上一页最大 id:
WHERE id > #{lastId} LIMIT 10。 - 延迟关联:
SELECT * FROM t INNER JOIN (SELECT id FROM t ORDER BY x LIMIT 1000000, 10) tmp ON t.id = tmp.id。
Q17:count 优化
count(*):MySQL 优化,推荐。count(1):类似。count(字段):不统计 null,慢。- 大表估算:
SHOW TABLE STATUS的 rows,或EXPLAIN。
Q18:避免 SELECT *
- 不走覆盖索引。
- 传输多余数据。
- 改变表结构可能影响。
Q19:JOIN 优化
- 小表驱动大表(小表在前)。
- JOIN 字段有索引。
- 控制JOIN 数量。
Q20:深分页 + 多条件
走"延迟关联"或"游标分页"。
五、设计与架构
Q21:三大范式
1NF 字段不可分、2NF 非主键完全依赖、3NF 非主键直接依赖(无传递)。
Q22:什么时候反范式
查询性能优先时,适当冗余字段,减少 JOIN。
Q23:分库分表
- 垂直:按业务拆库、按字段拆表。
- 水平:按 ID hash / 时间 / 范围拆分。
- 工具:ShardingSphere、MyCat。
Q24:分库分表后的问题
- 跨库 JOIN 难。
- 分布式事务。
- 全局唯一 ID(雪花算法)。
- 聚合查询难。
Q25:主从延迟
- 原因:单线程同步、网络、大事务。
- 解决:强制走主库、半同步复制、并行复制。
Q26:如何保证高可用
- 主从 + MHA / Orchestrator 故障切换。
- 读写分离 + 分库分表分散压力。
六、其他高频
Q27:MyISAM vs InnoDB
| MyISAM | InnoDB | |
|---|---|---|
| 事务 | 不支持 | 支持 |
| 锁 | 表锁 | 行锁 |
| 外键 | 不支持 | 支持 |
| 崩溃恢复 | 差 | 好 |
| 默认 | 否 | 是(5.5+) |
Q28:undo log / redo log / binlog
- redo log(InnoDB):崩溃恢复,crash-safe,循环写。
- undo log(InnoDB):回滚 + MVCC。
- binlog(Server 层):复制 + 备份,追加写。
Q29:两阶段提交
redo log 先 prepare → binlog 写盘 → redo log commit。保证 redo 和 binlog 一致。
高频考点速记
- 索引:B+ 树、聚簇/二级、覆盖、最左前缀、失效场景。
- 事务:ACID、四级别、MVCC、间隙锁。
- 三日志:redo(恢复)、undo(回滚/MVCC)、binlog(复制)。
- 优化:避免
*、分页用游标、JOIN 加索引。 - 分库分表:垂直拆业务、水平拆数据。