MySQL
MySQL(InnoDB)是国内互联网最常见的 OLTP 关系库之一。通用概念见 数据库;PostgreSQL 专篇可对照阅读。
InnoDB 核心
| 概念 | 面试怎么说 |
|---|---|
| 聚簇索引 | 主键索引叶子存整行;二级索引叶子存主键 |
| B+ 树 | 范围查询、顺序扫描友好 |
| MVCC | 读快照(Read View);undo log 存旧版本 |
| Redo / Undo | Redo 崩溃恢复;Undo 回滚与 MVCC |
| Buffer Pool | 内存缓存数据页与索引页 |
-- 覆盖索引:索引列包含查询列,减少回表
CREATE INDEX idx_user_email ON users(email, id);
EXPLAIN SELECT id FROM users WHERE email = 'a@b.com';
隔离级别与锁
默认 Repeatable Read(可重复读),InnoDB 用 Next-Key Lock(行锁 + 间隙锁)防幻读。
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 |
| 读已提交 | 否 | 可能 | 可能 |
| 可重复读 | 否 | 否 | InnoDB 多数场景防住 |
| 串行化 | 否 | 否 | 否 |
| 锁 | 场景 |
|---|---|
| 行锁 | 命中索引的更新 |
| 间隙锁 | 范围查询防插入 |
| 表锁 | DDL、无索引更新可能锁全表 |
索引实践
| 原则 | 说明 |
|---|---|
| 最左前缀 | 联合索引 (a,b,c) 可用 a、a,b,不能直接 b |
| 避免函数/on 列 | WHERE YEAR(created_at)=2024 难走索引 |
| 区分度 | 低基数列(性别)单独索引收益小 |
| 前缀索引 | 长字符串可前缀 + 覆盖常用列 |
主从复制
Master (binlog) ──→ IO Thread ──→ Relay Log ──→ SQL Thread ──→ Slave
| 模式 | 说明 |
|---|---|
| 异步复制 | 默认;主库不等从库确认 |
| 半同步 | 至少一个从库 ACK 再返回(插件) |
| GTID | 全局事务 ID,failover 更简单 |
复制延迟:写主读从可能 stale;关键读走主或带版本校验。
慢 SQL 排查
| 步骤 | 工具 |
|---|---|
| 找慢语句 | slow query log、performance_schema |
| 看计划 | EXPLAIN / EXPLAIN ANALYZE(8.0.18+) |
| 常见原因 | 无索引、索引失效、回表多、深分页 OFFSET |
深分页改 keyset:WHERE id > ? ORDER BY id LIMIT 20。
与 PostgreSQL 简对比
| 维度 | MySQL InnoDB | PostgreSQL |
|---|---|---|
| 默认隔离 | RR | Read Committed |
| 聚簇 | 主键聚簇 | 堆表 + 索引 |
| JSON | JSON 类型 | JSONB 索引更强 |
| 扩展 | 插件/分支多 | 扩展生态强 |
常见误解
- 「RR 绝对没有幻读」——当前读(
SELECT ... FOR UPDATE)仍可能遇到边界情况 - 「加索引一定快」——写放大、优化器选错、维护成本
- 「从库延迟可忽略」——读写分离要设计一致性策略
面试速记
- InnoDB 索引结构? B+ 树;聚簇索引存行;二级索引存主键。
- RR 怎么防幻读? MVCC + Next-Key Lock(间隙锁)。
- binlog 和 redo log? redo 物理页恢复;binlog 逻辑复制与 PITR。
- 慢查询怎么优化? EXPLAIN、索引、改写 SQL、拆表、缓存。
- 主从延迟怎么办? 同步策略、读主、缓存、业务容忍。