MySQL 高频面试题库
这份题库用于查漏补缺,不替代原理文档。先遮住“回答抓手”口述 30 秒,再沿追问讲 2 分钟,最后用 SQL 或项目案例证明。
基础、类型与建模
| # | 问题 | 回答抓手 |
|---|---|---|
| 1 | MySQL 的架构分几层 | 连接层、Server 层、存储引擎层;再串起解析、优化、执行和 InnoDB |
| 2 | InnoDB 和 MyISAM 有什么区别 | 事务、行锁、MVCC、外键、崩溃恢复、聚簇索引;现代业务默认 InnoDB |
| 3 | char 和 varchar 怎么选 | 定长/变长语义、长度、行格式、尾随空格与 collation,不说 char 查询一定快 |
| 4 | varchar 和 text 怎么选 | 最大长度、默认值/索引/临时表限制、是否频繁查询;按目标版本验证 |
| 5 | decimal 为什么适合金额 | 十进制定点精确;double 是二进制浮点,存在表示误差 |
| 6 | datetime 和 timestamp 区别 | 时区转换、表示范围、业务是绝对时间点还是本地时间 |
| 7 | utf8 和 utf8mb4 区别 | MySQL 历史 utf8 三字节;utf8mb4 完整 Unicode |
| 8 | collation 影响什么 | 比较、排序、大小写/重音、唯一键语义和索引结果 |
| 9 | 为什么建议显式主键 | 聚簇组织、复制/定位、隐藏主键代价;主键短、稳定、趋势递增 |
| 10 | 自增 ID 和 UUID 怎么选 | 局部性、页分裂、二级索引体积、分布式唯一与安全暴露的权衡 |
| 11 | NULL 有什么影响 | 三值逻辑、聚合忽略、索引与存储、业务语义;不机械要求全部非空 |
| 12 | 范式与反范式怎么选 | 范式减少冗余和更新异常;反范式换查询性能,但需一致性维护 |
| 13 | 唯一索引只是为了加速吗 | 首要是并发下保证约束,查询加速是附带收益 |
| 14 | 逻辑删除字段怎么设计 | 查询条件、联合索引、唯一性、归档、合规删除与数据膨胀 |
| 15 | 大字段为什么建议拆表 | 行页密度、Buffer Pool、网络、覆盖索引和冷热访问 |
SQL 与查询
| # | 问题 | 回答抓手 |
|---|---|---|
| 16 | SQL 逻辑执行顺序 | FROM/JOIN、WHERE、GROUP BY、HAVING、窗口、SELECT、ORDER BY、LIMIT |
| 17 | WHERE 与 HAVING 区别 | 分组前行过滤与分组后组过滤,能前推则尽早缩小输入 |
| 18 | count(*)、count(1)、count(col) | 前两者统计行,优化器处理通常相近;count(col) 忽略 NULL |
| 19 | EXISTS 和 IN 谁快 | 无绝对结论;半连接改写、NULL、数据分布、相关条件和索引 |
| 20 | NOT IN 有什么坑 | 子查询含 NULL 时三值逻辑;可用非空约束或 NOT EXISTS |
| 21 | UNION 与 UNION ALL | 前者去重有额外成本,后者保留重复;按业务语义选 |
| 22 | 窗口函数与 GROUP BY | 保留明细与折叠分组;排名、累计、环比场景 |
| 23 | CTE 一定提升性能吗 | 主要提升表达;合并/物化取决于版本和优化器,查看计划 |
| 24 | Join 的驱动表怎么判断 | 物理计划决定,不等同 SQL 左表;目标是小结果驱动且被驱动键有索引 |
| 25 | Left Join 条件放 ON 和 WHERE 区别 | ON 决定匹配,WHERE 过滤连接结果;右表条件可能把外连接变内连接 |
| 26 | N+1 怎么发现和解决 | APM/SQL 计数;批量查询、Join、预加载或 DataLoader,控制结果集 |
| 27 | 为什么不建议 select * | 网络、回表、覆盖索引、接口契约和大字段成本 |
| 28 | 深分页为什么慢 | 扫描并丢弃 offset;Seek/游标分页和稳定联合排序 |
| 29 | order by 相同值为什么会乱 | SQL 不保证同值顺序;追加唯一键形成全序 |
| 30 | 一条 SQL 更新太多行怎么办 | 按稳定键分批、控制事务与节奏、监控 redo/锁/复制,保证可恢复 |
索引与存储
| # | 问题 | 回答抓手 |
|---|---|---|
| 31 | 为什么用 B+Tree | 高扇出、树低、页 IO 少、有序叶子适合范围与排序 |
| 32 | B-Tree 与 B+Tree 区别 | 数据位置、扇出、叶子链;数据库文档命名常指 B-tree family |
| 33 | 聚簇索引是什么 | 主键叶子保存整行;表数据按其组织,一个表一个聚簇组织 |
| 34 | 二级索引叶子存什么 | 索引键和主键;查缺失列需回聚簇索引 |
| 35 | 什么是回表 | 二级索引取得主键后再次访问聚簇索引,成本取决于次数与局部性 |
| 36 | 什么是覆盖索引 | 所需列均可从索引获得;减少回表但不减少必然的范围扫描 |
| 37 | 最左前缀为什么成立 | 联合键按从左到右排序;跳过前列后后列整体无序,需结合版本特性 |
| 38 | 范围条件后列一定失效吗 | 用于定位的连续性可能中断,但后列仍可能 ICP/覆盖;看 key_len 与计划 |
| 39 | 索引下推 ICP 是什么 | 存储引擎在索引层先判断可用条件,减少回表,不等于减少全部扫描 |
| 40 | 索引失效有哪些场景 | 函数、隐式转换、前导模糊、低选择性、or、非匹配排序;都需计划验证 |
| 41 | 为什么有索引优化器不用 | 选择性差、回表多、统计信息、成本估计、返回比例和随机 IO |
| 42 | 索引越多越好吗 | 写放大、空间、Buffer Pool、页分裂、优化器成本;围绕高频 SQL 合并治理 |
| 43 | 前缀索引有什么代价 | 节省空间但区分度下降,通常不能完整覆盖/排序;评估基数 |
| 44 | 页分裂是什么 | 目标页空间不足时拆页搬移,增加写放大、碎片和日志;随机主键更易触发 |
| 45 | Change Buffer 做什么 | 缓存非唯一二级索引页的部分变更,减少随机 IO;不用于主键/唯一性立即检查 |
| 46 | Buffer Pool 缓存什么 | 数据/索引页、脏页等;命中、淘汰、刷脏和工作集决定性能 |
| 47 | 为什么 limit 20 可能扫描很多 | 过滤或排序前候选很多,limit 只限制最终返回,不保证访问行数 |
| 48 | Hash 索引为什么不能替代 B+Tree | 不支持范围、排序、前缀匹配;碰撞与持久化组织语义不同 |
优化器与执行计划
| # | 问题 | 回答抓手 |
|---|---|---|
| 49 | EXPLAIN 先看什么 | 访问顺序、type、key/key_len、rows/filtered、Extra,并结合业务返回量 |
| 50 | rows 是真实扫描行吗 | 是统计信息估算;用 EXPLAIN ANALYZE、慢日志核对实际 |
| 51 | type=ALL 一定差吗 | 小表或返回多数行可能合理;大表高频查询才危险,结合成本 |
| 52 | Using filesort 一定慢吗 | 表示不能直接按索引顺序完成;小结果内存排序可能可接受 |
| 53 | Using temporary 一定要优化吗 | 分组/去重等常见;关注规模、落盘、频率和内存,而非见词就改 |
| 54 | key_len 有什么用 | 判断使用联合索引的哪些字节;受类型、字符集、NULL、长度影响 |
| 55 | filtered 表示什么 | 经过访问方法后预计通过表条件的百分比;仍是估算 |
| 56 | EXPLAIN 与线上为何不同 | 参数、统计信息、缓存、并发、锁、版本和数据分布不同 |
| 57 | 如何更新统计信息 | analyze table;执行前评估版本行为和实例负载 |
| 58 | force index 应该用吗 | 可用于诊断/临时止损,不宜长期替代正确统计、SQL 和索引设计 |
| 59 | 慢 SQL 优化顺序 | 业务边界→真实证据→计划→减少扫描/回表/排序→验证副作用 |
| 60 | 为什么优化后写入变慢 | 新索引维护、页分裂、日志和缓存压力;读收益与写成本一起验收 |
事务、锁与 MVCC
| # | 问题 | 回答抓手 |
|---|---|---|
| 61 | ACID 如何实现 | undo/事务、约束、锁/MVCC、redo;一致性是综合目标 |
| 62 | MySQL 默认隔离级别 | InnoDB 常见默认 RR;以实例配置为准,不把默认当业务选择理由 |
| 63 | RC 与 RR 核心差异 | Read View 创建频率、快照一致性、范围锁行为 |
| 64 | MVCC 是什么 | 隐藏事务字段、undo 版本链、Read View 可见性;提升普通读并发 |
| 65 | 快照读与当前读 | 普通 select 读可见版本;加锁读和 DML 读最新并参与锁定 |
| 66 | 记录锁、间隙锁、临键锁 | 锁索引记录、间隙、记录加前间隙;范围受计划和隔离级别影响 |
| 67 | 行锁为什么会锁很多行 | 行锁基于索引;无合适索引或范围大时扫描和锁范围扩大 |
| 68 | RR 是否解决幻读 | 快照读靠 Read View,当前读靠 Next-Key;说明混用和边界 |
| 69 | 死锁怎么产生 | 形成等待环;不同顺序、范围锁、长事务、索引不当 |
| 70 | 死锁怎么排查 | InnoDB status/Performance Schema,还原事务、SQL、锁对象和顺序 |
| 71 | 死锁与锁等待区别 | 死锁有环会选牺牲者;锁等待可能最终获得锁或超时 |
| 72 | 乐观锁与悲观锁 | 版本条件更新与先锁后改;按冲突率、重试成本、事务长度选 |
| 73 | 长事务危害 | 持锁、undo/Purge、历史版本、回滚、复制和备份影响 |
| 74 | 如何防库存超卖 | 原子条件扣减并检查行数,或锁定;配合幂等和事务边界 |
| 75 | 事务里能调用远程服务吗 | 会延长持锁且远程操作不能随本地回滚;用本地事件/消息与补偿 |
日志、复制、备份与高可用
| # | 问题 | 回答抓手 |
|---|---|---|
| 76 | undo、redo、binlog 区别 | 回滚/MVCC、崩溃恢复、复制/PITR;层次与内容不同 |
| 77 | 为什么先写日志不直接刷数据页 | 顺序日志写成本低,提交与随机脏页刷盘解耦,靠 redo 恢复 |
| 78 | 两阶段提交为什么必要 | 协调 InnoDB redo 与 Server binlog 的事务一致性 |
| 79 | redo prepare 后宕机怎么办 | 结合 binlog 是否存在完整事务决定提交或回滚,讲清恢复判断 |
| 80 | binlog 三种格式 | statement、row、mixed;确定性、日志量、审计与复制安全权衡 |
| 81 | 组提交是什么 | 多事务合并 fsync,在保证顺序与一致性前提下降低刷盘次数 |
| 82 | 主从复制流程 | 主写 binlog、副本接收写 relay log、应用线程重放;MySQL 8 用 source/replica 术语 |
| 83 | 主从延迟原因 | 大事务、单线程依赖、IO/CPU、网络、从库慢查询、DDL、资源差异 |
| 84 | 写后读不到怎么办 | 读主、会话粘滞、等待 GTID、延迟路由、业务版本;不靠固定 sleep |
| 85 | GTID 解决什么 | 标识事务集合、切换来源和去重定位;不自动解决脑裂与业务幂等 |
| 86 | 异步与半同步区别 | 返回前是否等待副本收到日志;性能、RPO 与退化语义 |
| 87 | 复制是不是备份 | 不是,逻辑错误会传播;需要独立、可恢复、最好不可变的备份 |
| 88 | 逻辑备份与物理备份 | 可移植/细粒度但慢 vs 快且版本/平台约束更强 |
| 89 | PITR 怎么做 | 恢复全量基线,再按位置/GTID 回放 binlog 到目标时点或事务前 |
| 90 | 如何证明备份有效 | 定期隔离恢复、校验数据与业务、记录 RTO/RPO;备份成功日志不够 |
| 91 | 高可用切换关键步骤 | 检测、隔离旧主、比较事务集合、提升、路由、验证、重建 |
| 92 | 什么是脑裂 | 多节点同时接受写;必须 fencing,不能只靠“认为旧主挂了” |
生产治理与架构
| # | 问题 | 回答抓手 |
|---|---|---|
| 93 | Online DDL 为什么仍阻塞 | 起止阶段 MDL、长事务、算法退化、资源竞争 |
| 94 | INSTANT、INPLACE、COPY 区别 | 元数据、原地重建/扫描、复制表;按具体版本和操作验证 |
| 95 | 分区解决什么 | 裁剪与生命周期;仍是单实例,不自动提升所有查询 |
| 96 | 分区与分库分表区别 | 单实例逻辑表 vs 多物理节点;容量与复杂度边界不同 |
| 97 | 什么时候分库分表 | 先证明单机容量/吞吐瓶颈,普通 SQL 与归档优化已不足 |
| 98 | 分片键怎么选 | 高频路由、数据均匀、事务聚合、扩容;避免热点与广播 |
| 99 | 分片后全局分页为何难 | 各分片取数再归并,offset 和分片数放大中间结果 |
| 100 | 线上数据库突然变慢怎么排查 | 范围/时间线→业务/主机/数据库分层→SQL/锁/IO证据→止损→验证 |
十道场景题
1. 支付回调重复到达
回答要包含:支付流水业务唯一键、订单状态机条件更新、事务内本地事件、检查受影响行数、重复请求返回已有结果、对账与补偿。
2. 库存偶尔变成负数
检查是否“先查后扣”、事务边界和重试;改为 update ... set stock=stock-? where stock>=?,检查影响行数;高冲突时评估串行化入口、热点拆分和排队。
3. 有联合索引但列表接口仍慢
用真实参数看索引使用长度、扫描范围、回表、排序、深分页和数据倾斜;索引围绕等值过滤、范围和排序设计,必要时改 Seek 分页,最后比较 P99 与写成本。
4. 发布后数据库连接打满
先限流并定位连接来源;检查连接池总规模、泄漏、慢 SQL、锁等待和重试风暴。不要只增大服务端连接数,要让所有实例连接池总和受数据库容量约束。
5. 加字段把线上表卡住
还原 MDL 阻塞链和长事务,评估取消 DDL或终止根阻塞者;之后验证目标版本算法,设置超时,低峰变更,监控复制和资源,并采用向前兼容发布顺序。
6. 主库故障准备切从库
先隔离旧主防脑裂,比较 GTID 和延迟,选最完整健康副本,提升并切流,验证读写,再重建拓扑;明确异步复制下的可能数据丢失和补偿。
7. DBA 误删订单
立即停止继续破坏并保留证据,不直接覆盖生产;恢复最近全量备份到隔离实例,回放 binlog 到误删前,核对数据后通过受控脚本回补,再复盘权限与审批。
8. 从库延迟不断增长
判断是接收慢还是应用慢,检查大事务、DDL、并行复制、硬件、网络和从库查询;强一致读临时走主,拆小事务或隔离重查询,不能随意跳过事务。
9. 历史订单占用数 TB
先定义在线/归档保留和查询 SLA,再分批迁移校验;按访问模式选择时间分区、归档库或 OLAP,不一上来分片。删除过程监控日志、锁和复制延迟。
10. 用户表 JSON 属性越来越慢
识别高频过滤、排序和约束字段,将稳定字段关系化;少数路径用类型明确的生成列/函数索引;评估 JSON 文档大小、更新写放大和统计信息,复杂搜索转专用系统。
最终口述验收
随机抽 20 题,每题按下面标准评分:
- 1 分:能给出正确定义。
- 1 分:能讲完整机制或流程。
- 1 分:能指出边界和常见误区。
- 1 分:能给 SQL、命令或监控证据。
- 1 分:能联系真实项目并说明方案副作用。
达到 80 分以上,才算具备“能灵活应对追问”的基础;答错后不要背答案,回到对应原理页完成最小复现实验。
