数据库面试题
MySQL
1. 索引的底层数据结构是什么?为什么用 B+Tree?
MySQL InnoDB 引擎使用 B+Tree 作为索引结构。
为什么用 B+Tree?
- 相比二叉树,B+Tree 是多路搜索树,高度更低,减少磁盘 IO
- 相比 B-Tree,B+Tree 非叶子节点只存索引,单节点存储更多索引,降低树高
- 叶子节点形成有序链表,支持范围查询
- 所有数据存储在叶子节点,查询效率稳定
2. 聚簇索引和非聚簇索引的区别?
| 类型 | 聚簇索引 | 非聚簇索引 |
|---|---|---|
| 叶子节点存储 | 完整行数据 | 主键值 |
| 数量限制 | 一个表只能有一个 | 可以有多个 |
| 是否需要回表 | 不需要 | 可能需要 |
| 默认创建 | 主键自动创建 | 手动创建 |
3. 什么是回表?如何避免?
回表:通过非聚簇索引查询时,先查到主键值,再通过主键去聚簇索引查找完整数据的过程。
避免方法:使用覆盖索引,即查询的列都在索引中,无需回表。
sql
-- 假设建立了 (name, age) 联合索引
SELECT name, age FROM user WHERE name = '张三'; -- 覆盖索引,无需回表
SELECT * FROM user WHERE name = '张三'; -- 需要回表4. MySQL 事务隔离级别有哪些?
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 会 | 会 | 会 |
| READ COMMITTED | 不会 | 会 | 会 |
| REPEATABLE READ(默认) | 不会 | 不会 | 会(部分解决) |
| SERIALIZABLE | 不会 | 不会 | 不会 |
InnoDB 的 REPEATABLE READ 通过 MVCC + Next-Key Lock 基本解决了幻读。
5. 慢查询如何优化?
- 开启慢查询日志,定位慢 SQL
- 使用 EXPLAIN 分析执行计划,重点关注 type、rows、Extra
- 检查是否命中索引,必要时添加索引
- 避免 SELECT *,返回必要字段
- 优化分页(深分页用子查询或游标)
- 大表考虑分库分表
Redis
6. Redis 为什么这么快?
- 纯内存操作:数据存储在内存中
- 单线程模型:避免上下文切换和锁竞争(Redis 6.0 后引入多线程 IO)
- IO 多路复用:epoll 模型处理高并发连接
- 高效的数据结构:SDS、压缩列表、跳表等
7. 如何保证缓存与数据库的一致性?
- Cache Aside 模式:先更新数据库,再删除缓存
- 延迟双删:先删缓存 → 更新数据库 → 延迟再删缓存
- 读写锁:写操作加锁,读操作无锁
- 最终一致性方案:使用 Canal 监听 binlog 异步更新缓存