主题
面试题蒸馏卡:MySQL
从丁奇《MySQL实战45讲》+ hxq-note 底层原理约 120 篇提炼的高频面试题。每题按「标准答 → 追问链 → 常见误解」组织。
Q1:一条 SQL 是怎么执行的?
标准答:MySQL 分 Server 层 + 存储引擎层。一条查询走:连接器(认证/查权限)→ 查询缓存(8.0 已移除)→ 分析器(词法+语法解析)→ 优化器(选索引/定 join 顺序)→ 执行器(调引擎接口取数)。
追问链:
- "为什么查询缓存被移除?" → 失效太频繁(一有更新全表缓存清空),命中率低
- "执行器怎么取数据?" → 调引擎「取第一行/下一行」接口循环,rows_examined 记扫描行数
- "长连接有什么坑?" → 连接内存断开才释放,累积 OOM;用 mysql_reset_connection 重置
常见误解:❌ 以为查询缓存很有用;❌ 以为改权限立即生效(连接时读取)。
Q2:MySQL 为什么用 B+ 树做索引?
标准答:B+ 树是 N 叉树(InnoDB 的 N≈1200),树高极低——树高 4 能存 17 亿,查一个值最多读 3 次磁盘;而二叉树 100 万节点树高 20,要读 20 个数据块。哈希表只适合等值查询(无序),有序数组只适合静态数据(插入慢)。
追问链:
- "聚簇索引和二级索引区别?" → 聚簇叶子存整行,二级叶子存主键值;二级索引查要回表
- "回表是什么?怎么避免?" → 二级索引查主键再回主键树查整行;用覆盖索引避免
- "为什么推荐自增主键?" → 追加插入不触发页分裂,且主键短让二级索引叶子小
常见误解:❌ 以为索引在内存里(在磁盘,才选多叉树降树高)。
Q3:事务隔离级别和 MVCC?
标准答:4 级——读未提交/读已提交/可重复读/串行化。MVCC 靠 undo log + Read View 实现:RR 事务启动时建视图(全程一致),RC 每条 SQL 建视图(能看到别人提交)。
追问链:
- "RR 和 RC 的核心区别?" → Read View 创建时机(事务启动 vs 每条 SQL)
- "长事务有什么危害?" → 回滚日志不能清理,磁盘膨胀 + 占锁
- "怎么查长事务?" →
information_schema.innodb_trx查持续时间
常见误解:❌ 以为 MVCC 靠锁实现(是快照读,无锁)。
Q4:MySQL 的锁和死锁?
标准答:行锁遵循两阶段锁协议(需要时加、事务结束才释放)。死锁靠 innodb_deadlock_detect 主动检测回滚,但热点行更新时检测开销 O(n²) 吃 CPU。
追问链:
- "怎么减少锁冲突?" → 把冲突大的锁往后放;控制并发度;一行拆多行
- "死锁检测为什么吃 CPU?" → 每个被堵线程都做 O(n) 检测,n 个线程就是 O(n²)
- "MyISAM 为什么并发差?" → 只支持表锁,不支持行锁
常见误解:❌ 以为行锁用完就释放(事务结束才释放)。
Q5:redo log 和 binlog 的区别?两阶段提交为什么?
标准答:redo log 是 InnoDB 物理日志(循环写,崩溃恢复),binlog 是 Server 层逻辑日志(追加写,归档主从)。两阶段提交(redo prepare → 写 binlog → redo commit)保证两者逻辑一致,否则崩溃后「库状态」和「日志恢复的库」不一致。
追问链:
- "WAL 是什么?" → Write-Ahead Logging,先写日志再写磁盘,随机写变顺序写
- "怎么保证不丢数据?" → innodb_flush_log_at_trx_commit=1 + sync_binlog=1
- "redo 循环写写满了怎么办?" → 推进 checkpoint,擦除前先刷盘
常见误解:❌ 以为两阶段提交为性能(是为一致性);❌ 以为 binlog 是物理日志。
Q6:MySQL 主从复制和一致性?
标准答(衔接 MySQL技术栈总览):主库写 binlog,从库拉取 binlog 重放(IO 线程拉取 + SQL 线程执行)。主从延迟源于从库 SQL 线程串行重放慢于主库并发写,5.7 起用并行复制(按库/组提交)加速。
追问链:
- "主从延迟怎么解决?" → 并行复制、读写分离 + 强制走主库(关键读)
- "binlog 三种格式?" → statement/row/mixed,row 最安全
常见误解:❌ 以为主从是同步的(默认异步,有延迟)。