数据库源码面试考点?

访客 源码剖析 1

本文目录导读:

  1. 存储引擎与索引(最常考,占比约40%)
  2. 事务与并发控制(进阶,约30%)
  3. 查询优化与执行器(约20%)
  4. 工业级特性与源码构件(约10%)
  5. 常见面试真题模拟(含思路)
  6. 总结与建议

数据库源码面试是后端工程师面试中难度较高的一类,主要考察对存储、索引、事务、并发控制等核心机制的理解深度,能直接手撕B+树或MVCC源码的候选人,往往是面试官眼中的高分选手。

以下是整理的核心考点,按照基础实现高级特性并发与事务工业级优化四个维度分类:

存储引擎与索引(最常考,占比约40%)

这是数据库的基石,面试官会从“人肉执行一条SQL”的角度来考察。

  1. B+ 树实现细节

    • 阶数选择:为什么是B+树而不是二叉树或B树?如何计算一个3层B+树能存多少数据(2000w行左右)?
    • 叶子节点:双向链表的作用(范围查询优化)、数据存储方式(聚簇索引 vs 二级索引)。
    • 分裂与合并:页分裂的时机、代价(I/O操作、页写满时的数据搬运)、页合并的触发条件(删除导致数据稀疏)。
    • 自适应哈希:InnoDB如何判断热点页并构建哈希索引(需要具备并发安全的惰性构建能力)。
  2. 索引组织表

    • 聚簇索引:主键为什么建议自增?UUID作为主键会导致页分裂频繁与空间浪费。
    • 二级索引回表:回表次数、MRR(Multi-Range Read)优化(将随机I/O转顺序I/O)。
    • 覆盖索引:查询字段都在索引中,无需回表。
  3. Buffer Pool(缓冲池)

    • LRU 算法变种:MySQL为什么要使用分代的LRU(InnoDB的LRU链表被分为New和Old两个子列表,防止预读污染)。
    • 脏页刷新:Checkpoint机制(WAL前提)、Flush List、刷脏策略控制(innodb_io_capacity)。

事务与并发控制(进阶,约30%)

重点考察ACID的实现细节,特别是隔离性持久性

  1. MVCC(多版本并发控制)

    • 实现核心trx_id(事务ID)、roll_pointer(回滚指针)、ReadView(读视图)。
    • ReadView 创建时机:RC(Read Committed)级别下每次查询都创建;RR(Repeatable Read)级别下只在事务第一次查询创建。
    • 可见性判断:当前行的 trx_idm_ids 列表还是小于 up_limit_id?能否活跃在该ReadView后写入的新版本?
  2. 锁机制

    • 行锁实现:Record Lock、Gap Lock、Next-Key Lock(怎么通过锁解决幻读的?)。
    • 锁升级:InnoDB什么时候从行锁升级到表锁(很少,除非无法确定索引)?
    • 死锁检测wait-for graph(等待图)如何检测死锁?innodb_deadlock_detect 的代价(高并发下可能拖垮性能)。
  3. 日志系统(WAL)

    • Redo Log(重做日志):物理日志(记录页的修改)、min-transaction 组提交、LSN(Log Sequence Number)机制。
    • Undo Log(回滚日志):逻辑日志、用于事务回滚和MVCC快照读。
    • Binlog:与Redo Log的区别与协同(两阶段提交,崩溃恢复保证一致性)。

查询优化与执行器(约20%)

虽然面试中较少直接手撕优化器源码,但这些考点通常出现在场景题压轴问题中。

  1. 优化器

    • 代价模型CPU Cost + IO Cost,如何估算扫描行数和选择度(Cardinality 统计信息)?
    • Join 算法:Nested Loop Join、Hash Join(MySQL 8.0引入)、Sort Merge Join分别在什么场景触发?
    • ICP(Index Condition Pushdown,索引条件下推):如何将WHERE条件推送到存储引擎层,减少回表次数。
  2. 执行器

    • 接口交互:存储引擎如何根据“下一行记录”接口返回数据给执行器。
    • using filesort:内存排序(sort_buffer)与磁盘排序(归并排序)的触发条件。

工业级特性与源码构件(约10%)

这部分更考验对开源项目(如MySQL、PostgreSQL、TiDB)实际代码库的理解。

  • 插件式存储引擎handler 接口的设计哲学。
  • 内存池与内存分配:InnoDB如何管理大页(Huge Page)、buf_block_t 结构体、AIO(Async I/O)实现。
  • DDL(Data Definition Language,数据定义语言)操作:Online DDL(如Instant ADD COLUMN)的实现原理(涉及到 fspdict 系统表的改动)。
  • TiDB / CockroachDB:分布式数据库的Raft协议实现、Percolator事务模型(Go语言实现,但核心算法与关系数据库不同)。

常见面试真题模拟(含思路)

  1. Q:MySQL 删除一张1000W行的表,直接DROP TABLEDELETE FROM table,底层行为有什么区别?

    • 考点:Buffer Pool的回收、Undo Log的生成、truncate修改表空间元数据(.ibd 文件回收)。
    • 思路DROP是DDL,直接释放段空间(重新初始化,相当于rm文件),效率极高;DELETE是DML,维护MVCC(生成Undo),需要逐行标记删除。
  2. Q:RR隔离级别下,SELECT...FOR UPDATESELECT...LOCK IN SHARE MODE 如何防止幻读?

    • 考点:Next-Key Lock的锁定范围。
    • 思路:在RR级别,对间隙(Gap)加锁(Gap Lock),阻止其他事务插入;FOR UPDATE加的是X锁(写锁),LOCK IN SHARE MODE加的是S锁(共享锁)。
  3. Q:当我们执行 UPDATE t SET a=2 WHERE id=1 时,InnoDB的崩溃恢复是如何保证 a 最终是2而不是其他值的?

    • 考点:WAL + Redo Log的两阶段提交。
    • 思路:1. 写入Undo(用于回滚);2. 修改内存中的Page(buf_pool);3. 生成Redo Log(状态为 prepare);4. 写入Binlog;5. 提交事务(Redo Log状态置为 commit),崩溃恢复时检查Redo Log状态和Binlog的一致性。
  4. Q:数据库连接池(如 HikariCP 或 libmysqlclient 的线程模型)的线程安全是如何在源码层面保证的?

    • 考点:锁的粒度(mutex / rw_lock)以及C/S端协议的互斥。
    • 思路:每个连接(THD 对象)在MySQL内部绑定了线程ID,通过 thr_lock.c 中的表锁和 row_lock 实现并发控制;连接池本身受 pthread_mutex_t 保护。

总结与建议

  • 目标与策略:如果目标是大厂高级岗位,建议从 Buffer Pool 替换算法(如 Clock-sweep)、B+树分裂合并的 C代码实现(btr_page_split_and_merge)入门,如果只是中级开发,能清晰讲出MVCC和Redo Log的原理就是及格线。
  • 最佳实践:阅读 MySQL 5.7/8.0 的开源代码,重点关注 storage/innobase 目录下的 btr(B-tree)、row(行操作)、lock(锁)、trx(事务)模块,也可以结合 《High Performance MySQL》、《数据库系统概念》的理论知识相互印证。

如果你只想深入准备一个最常考的点,建议优先攻克 MVCC 下的 ReadView 可见性判断 + 行锁(Record/Gap/Next-key Lock),这是面试官判断候选人源码功底的分水岭。

标签: 面试考点

抱歉,评论功能暂时关闭!