MySQL FAQ
内容:
- 基础
- 索引 / 锁 / 事务 / 隔离级别
- MVCC 底层
- 日志(redo/undo/binlog)
- SQL 优化
- 主从复制与一致性
- 存储引擎
- 高可用 / 集群
目录
- MySQL 基础
- InnoDB 索引
- InnoDB 锁
- 事务与隔离级别
- 日志系统(undo/redo/binlog)
- MVCC
- SQL 调优
- 主从复制
- 高可用方案
- 大表优化
- 存储引擎对比
- 综合“难度提升题”
🔥 InnoDB 是 MySQL 默认引擎,支持:
- 事务(ACID)
- 行级锁(最小锁粒度)
- MVCC(高并发)
- 外键
- B+Tree 索引
- redo + undo 持久化机制
其它存储引擎:
| 引擎 | 特点 |
|---|---|
| MyISAM | 不支持事务、表级锁、读取快、崩溃可能丢数据 |
| Memory | 数据在内存、极快、重启丢失 |
| Archive | 仅支持 INSERT/SELECT(归档) |
- char 固定长度:适合身份证号、MD5 等定长字段
- varchar 可变长度:节省空间,适合字符串
- FLOAT:不精确,浮点运算
- DECIMAL:精确计算(金融金额用它)
索引是用 B+Tree 组织的数据结构,使得:
- 查找复杂度从 O(n) -> O(log n)
- 范围查找连续(叶子节点链表)
- 只有叶子节点存储数据(B-Tree 每个节点都存储数据)
- 非叶节点更小 -> 一个页面能存更多节点 -> 树更矮
- 顺序链指针支持 范围查询(BETWEEN/LIKE ‘xxx%’)
- 精确匹配
- 范围查询(>, <, between)
- 前缀查询(like ‘abc%’)
- join on 字段
- order by 可优化(索引有序)
- 函数操作:where DATE(create_time) = ‘2024-01-01’
- 字段类型不一致:age = ‘20’
- 左模糊:LIKE ‘%abc’
- OR 前后字段不一致
- 负向查询:!=, <>, NOT IN
因为 B+Tree 是按:(a,b,c) 从左到右排序组织的,不知道 a 的值,就无法定位 b,c。
查询字段全部在二级索引里,直接从 索引树 返回,不回表,速度极快。
例如:
SELECT id, name FROM user WHERE name='abc';
如果 name 是二级索引 -> 覆盖索引。
非主键索引只能取到主键,再去主键 B+Tree 中查真实行数据。
多一次 IO -> 较慢。
按照粒度:
- 表锁
- 行锁(Record Lock)
- 间隙锁(Gap Lock)
- Next-Key Lock(Record + Gap)
范围查询:
UPDATE ... WHERE age BETWEEN 10 AND 20;
DELETE ...
-> 自动加 Next-Key Lock(阻止 INSERT/UPDATE/DELETE)
单点查询:
UPDATE ... WHERE id=1;
-> 加 记录锁
死锁:两个事务互相占有锁,导致互相等待。
解决:
- 缩小锁范围
- 减少范围查询
- 固定访问顺序
- 使用更小的事务
- Atomicity(原子性)
- Consistency(一致性)
- Isolation(隔离性)
- Durability(持久性)
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✅ | ✅ | ✅ |
| READ COMMITTED | ❌ | ✅ | ✅ |
| REPEATABLE READ(默认) | ❌ | ❌ | ✅ (用Next-Key) |
| SERIALIZABLE | ❌ | ❌ | ❌ |
使用 Next-Key Lock(记录锁 + 间隙锁)锁住范围,阻止范围内 INSERT。
重启后恢复未刷盘的数据 -> 保证 持久性(D)
undo log 用来:
- MVCC 版本链
- 事务回滚
| 内容 | redo log | binlog |
|---|---|---|
| 层级 | InnoDB 引擎 | MySQL Server 层 |
| 作用 | 崩溃恢复 | 主从复制 / 审计 |
| 是否覆盖 | 循环写 | 追加写 |
| 写入时机 | 事务中多次写 | 提交时一次写 |
保证:
redo log 与 binlog 一致
事务提交流程:
- 写 redo(prepare)
- 写 binlog
- redo commit
依靠:
- undo log(旧版本)
- read view(可见性规则)
- hidden columns(trx_id / roll_pointer)
- 高并发查询(SELECT 无需加锁)
- 避免读写冲突
- 快照读
- EXPLAIN
- SHOW PROFILE
- trace 优化器
- performance_schema
- slow log(慢 SQL)
| 字段 | 意义 |
|---|---|
| type | 系统/const/ref/range/index/ALL |
| key | 使用的索引 |
| rows | 扫描行数估计 |
| extra | 是否 Using index 等 |
- 遵循索引顺序
- where 和 order by 使用同一索引
- 避免 filesort
InnoDB 做了优化:不取出行内容,直接按行扫描(可能利用二级索引)
- master 写入 binlog
- replica IO 线程把 binlog 拉到 relay log
- SQL 线程执行 relay log
- 设置 sync_binlog=1
- 设置 innodb_flush_log_at_trx_commit=1
- semisync 半同步
- MGR(官方,强一致)
- InnoDB Cluster(MGR 封装)
- Semi-Sync(半同步)
- MHA(自动切换)
- Orchestrator(大规模集群)
- PXC / Galera(强一致)
- 分区(range/hash)
- 垂直/水平拆分
- 索引优化
- 增量归档(按月备份)
- 热/冷分离
- 按时间分表
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务 | ✅ | ❌ |
| 行锁 | ✅ | ❌(只有表锁) |
| 崩溃恢复 | ✅ | ❌ |
| 外键 | ✅ | ❌ |
- 范围查询差
- 不支持排序
- 不支持前缀匹配
- 不支持多列联合索引
保证:
- 先写日志,后写数据页
- 崩溃恢复更快(redo log)
避免:
- 崩溃造成数据丢失
- 数据页部分写入导致页损坏
加读锁 -> 全局锁 -> 读写冲突 -> 并发能力极差
MVCC -> 非锁定一致性读
show processlist;
show engine innodb status \G;
performance_schema.data_locks
竞争 DDL,解决:
- 避免业务高峰执行 DDL
- 使用 pt-online-schema-change
- 使用 gh-ost