MySQL 核心原理与高频面试题

在数据库常见面试问题中,MySQL 无疑是考察频率最高的部分。面试官往往不仅关注 SQL 语句的编写,更侧重于底层存储引擎、索引结构以及事务隔离级别的深入理解。以下整理了最具代表性的三个核心考点。

索引结构
事务隔离
Binlog 机制

为什么 MySQL 使用 B+树 而不是 B树 或 哈希?

B+树是 InnoDB 存储引擎默认索引结构。相较于 B树,B+树 的非叶子节点只存储键值,不存储数据,这使得单个节点能容纳更多的索引项,从而降低了树的高度,减少了磁盘 I/O 次数。

  • ⚡ 范围查询优势: B+树 叶子节点通过双向链表连接,非常适合范围查询(Range Scan),而 B树 需要进行中序遍历,效率较低。
  • ⚡ 查询稳定性: B+树 的所有查询都必须走到叶子节点,性能更加稳定。
  • ⚡ 哈希索引局限: Hash 索引仅适用于等值查询,无法支持范围查询和排序,且存在哈希冲突问题。
特性 B+树 B树 Hash
非叶子节点存储 仅键值 键值+数据 N/A
范围查询 支持 (高效) 支持 (较慢) 不支持
排序性能 天然有序 需额外排序 无序

事务隔离级别与并发问题

数据库常见面试问题中,事务隔离级别是必考题。SQL 标准定义了四种隔离级别,MySQL 默认采用 Repeatable Read (可重复读)。

  1. Read Uncommitted (读未提交): 会出现脏读、不可重复读、幻读。
  2. Read Committed (读已提交): Oracle 默认。解决脏读,但仍存在不可重复读和幻读。
  3. Repeatable Read (可重复读): MySQL 默认。通过 MVCC 解决脏读和不可重复读,通过 Next-Key Lock 解决大部分幻读。
  4. Serializable (串行化): 最高级别,解决所有并发问题,但性能极差,不推荐使用。

注:在 RR 级别下,MySQL 通过 MVCC(多版本并发控制)和 Gap Lock(间隙锁)机制来保证事务的隔离性。

MGR 与 Binlog 的协同工作

Binlog 是 MySQL 服务端产生的日志,记录所有修改数据的 SQL 语句。它与 InnoDB 的 Redo Log 和 Undo Log 共同构成了 MySQL 的事务持久性和原子性基础。

  • ⚙️ Redo Log: InnoDB 引擎特有,物理日志,保证崩溃恢复(Crash-Safe)。
  • ⚙️ Undo Log: 逻辑日志,用于事务回滚和 MVCC 实现。
  • ⚙️ Binlog: 逻辑日志,用于主从复制和数据恢复。

在 MGR(MySQL Group Replication)中,Binlog 还承担着组内成员间状态同步的重要职责。

Redis 缓存策略与数据库常见面试问题

随着分布式系统的普及,Redis 已成为数据库常见面试问题中不可或缺的一环。面试官通常关注缓存穿透、击穿、雪崩的解决方案,以及 Redis 与数据库的双写一致性。

缓存穿透

指查询一个根本不存在的数据,缓存和数据库中都没有,导致每次请求都打到 DB。解决方案:布隆过滤器(Bloom Filter)或缓存空对象。

缓存击穿

指某个热点 Key 在过期瞬间,大量请求同时到达,导致 DB 压力激增。解决方案:设置热点 Key 永不过期,或使用互斥锁(Mutex Key)。

缓存雪崩

指大量 Key 同时过期 或 Redis 宕机。解决方案:过期时间加随机值,使用 Redis 集群高可用架构。

双写一致性

先更新数据库,再删除缓存(而非更新缓存)。若删除失败,需通过消息队列重试。推荐使用 Canal 订阅 Binlog 异步更新缓存。

SQL 性能优化实战

在实际工作中,SQL 优化是数据库常见面试问题中的实操重点。以下提供几个典型的优化场景及示例。

1. 索引失效的场景

  • ⚡ 对索引列进行函数运算或表达式计算。
  • ⚡ 隐式类型转换(如字符串不加引号)。
  • ⚡ 模糊查询以 % 开头(如 LIKE '%abc')。
  • ⚡ OR 条件中,若有一个字段无索引,则整体索引失效。

2. 执行计划分析示例

使用 EXPLAIN 关键字分析 SQL 执行效率,重点关注 type、key、rows 和 Extra 字段。

EXPLAIN SELECT  FROM orders WHERE user_id = 1001 AND status = 'paid';
字段 说明 理想值
type 访问类型,性能从好到坏:system > const > eq_ref > ref > range > index > all ref 或 range
key 实际使用的索引 非 NULL
rows 预估扫描行数 越小越好
Extra 额外信息 避免 Using filesort 和 Using temporary

数据库架构设计与分库分表

当数据量达到千万级甚至亿级时,单机 MySQL 难以承载,分库分表成为数据库常见面试问题中的高级考点。

阶段一:垂直拆分

将用户表、订单表、商品表等拆分到不同的数据库中,解决单库连接数瓶颈和热点数据问题。

阶段二:水平拆分(Sharding)

将单张表的数据按照某种规则(如 user_id % 16)分散到多个表中。常用中间件:ShardingSphere、MyCat。

阶段三:读写分离

主库负责写,从库负责读。通过 Binlog 同步数据,提升读吞吐量。注意主从延迟问题。

分库分表的挑战

  • ⚡ 跨库 Join: 避免跨库关联查询,尽量通过冗余字段或应用层组装数据。
  • ⚡ 全局 ID: 使用雪花算法(Snowflake)生成唯一 ID,避免主键冲突。
  • ⚡ 分布式事务: 使用 Seata 等框架保证数据一致性,或采用最终一致性方案(如本地消息表)。