📖 本篇简介:本篇收录 20 道面试中出现频率不高但答出来很加分的 MySQL 题,覆盖索引、锁、日志、架构、运维的冷门细节。这些题答出来,面试官会觉得你"不仅背过八股,还真懂"。本文基于 MySQL 8.0。
目录
- 1 使用说明
- 2 冷门加分题1至5
- 3 冷门加分题6至10
- 4 冷门加分题11至15
- 5 冷门加分题16至20
- 6 加分题汇总表
- 7 自测练习
1 使用说明
这 20 道题不是高频必考题,但答出来就是加分项。面试时答出一两个冷门细节,面试官对你的评价会从"背过八股"升级为"真的深入研究过"。
答题策略:这些题不用全背,理解原理后能说出大概即可。下表是题目难度分布。
| 难度 | 数量 | 占比 |
|---|---|---|
| 容易想到 | 5 | 25% |
| 需要思考 | 10 | 50% |
| 很冷门 | 5 | 25% |
2 冷门加分题1至5
题目 1:InnoDB 的页为什么默认 16K?
考点:InnoDB 存储架构。
参考答案:16K 是折中。太小(如 4K)一次 IO 读的数据少,范围查询要读很多页;太大(如 64K)单行数据占不满页,浪费空间。16K 匹配机械盘扇区和 SSD 块大小,范围查询和点查都平衡。8.0 支持启动参数调整页大小。
加分点:提到"页是 InnoDB 磁盘读写最小单位,redo log 也是按页记录修改"。
题目 2:change buffer 只缓存什么索引?
考点:InnoDB 写优化。
参考答案:只缓存二级索引(非唯一)。聚簇索引的页本来就要读入 Buffer Pool,不用缓存。唯一索引因为要校验唯一性,也必须立即读盘,用不了 change buffer。
加分点:提到 change buffer 会在缓冲池有空闲时合并写盘。
题目 3:什么是预读?
考点:InnoDB 读优化。
参考答案:InnoDB 预测性地一次读相邻几个页。线性预读:顺序读了 13 个页就预读下一区间;随机预读:一个区里 16 个页都在缓冲池就预读下一区。目的是把随机读变顺序读。
加分点:提到预读可能浪费,8.0 默认关了随机预读。
题目 4:什么是 flushed 脏页刷新的双 write?
考点:崩溃恢复。
参考答案:脏页先写到 doublewrite 区,再写真实位置。防止写一半断电导致页损坏。崩溃恢复时从 doublewrite 区拿完整页。
加分点:提到 SSD 也建议开,因为文件系统块也可能写坏。
题目 5:InnoDB 的事务 ID 是怎么分配的?
考点:MVCC。
参考答案:每个事务启动时分配一个单调递增的 trx_id。读视图记录当时活跃的事务 ID 列表,判断行版本对当前事务可见不可见。
加分点:提到只读事务不分配 trx_id,节省开销。
3 冷门加分题6至10
题目 6:什么是 purge 线程?
考点:MVCC 清理。
参考答案:后台线程清理已经不再被任何读视图需要的 undo log 旧版本。如果 undo 堆积,purge 跟不上,会导致回滚段膨胀、查询变慢。
加分点:提到 purge lag 监控指标。
题目 7:什么是 adaptive hash index?
考点:InnoDB 自动优化。
参考答案:InnoDB 监测到某些页被频繁等值查询,自动在内存里建哈希索引,把 B+树查找变成 O(1)。不需要人工干预。
加分点:提到高并发等值查询时可以观察 AHI 命中率。
题目 8:什么是 insert 意图锁?
考点:间隙锁细分。
参考答案:插入记录前,事务会在插入位置加一个"插入意图锁",告诉别的事务"我准备往这插"。别的事务如果要锁这个间隙,会被阻塞。它是间隙锁的一种。
加分点:提到它减少了幻读冲突。
题目 9:什么是 semi-consistent read?
考点:锁与读。
参考答案:更新语句在遇到行锁时,如果该行已经提交了新版本,会读最新版本再判断。减少锁等待。5.6 后引入。
加分点:提到它只在 RC 和 RR 下行为不同。
题目 10:什么是 MDl 锁?
考点:表级元数据锁。
参考答案:MySQL 5.5 引入 Metadata Lock。访问表时加 MDl,DDL 修改表结构时要等所有 MDl 释放。防止 DDL 中途和查询冲突。
加分点:提到长事务会阻塞 DDL,MDl 排队。
4 冷门加分题11至15
题目 11:什么是 tablespace 加密?
考点:安全合规。
参考答案:8.0 支持 InnoDB 表空间透明加密,数据文件落盘是密文,内存里明文。等保合规常用。
加分点:提到密钥管理用 keyring 插件。
题目 12:什么是 redo log 的 group commit?
考点:日志刷盘优化。
参考答案:多个事务的 redo 写入合并成一次 fsync,减少刷盘次数。组提交是高并发写入性能的关键。
加分点:提到 binlog 组提交和 redo 组提交的配合。
题目 13:什么是半同步复制的损失?
考点:高可用。
参考答案:半同步复制要等至少一个从库确认收到 binlog,主库提交。比异步多了网络往返延迟,但宕机丢数据风险小。
加分点:提到半同步超时后自动降级异步。
题目 14:什么是 GTID 的 transaction set?
考点:复制原理。
参考答案:每个 GTID 对应一个事务,从库通过对比主库的 executed_gtid_set,知道自己缺哪些事务,自动补齐。切换时不用找 binlog 位点。
加分点:提到 GTID 复制更适合自动化切换。
题目 15:什么是 MHA 的二次切换?
考点:高可用工具。
参考答案:MHA 检测主库宕机后,选最新从库提升为主,其他从库重新指向新主。处理主从延迟数据补全。
加分点:提到 MHA 有个问题是切换时会有短暂写入丢失风险。
5 冷门加分题16至20
题目 16:什么是 information_schema 的 InnoDB 表?
考点:8.0 数据字典。
参考答案:8.0 把元数据存在 InnoDB 内部表,information_schema 视图直接查这些内部表,比 5.7 遍历 frm 文件快很多。
加分点:提到 8.0 的 data dictionary 是事务化的。
题目 17:什么是降序索引?
考点:8.0 新特性。
参考答案:5.7 写 DESC 建索引语法会忽略,实际还是升序。8.0 真正支持降序存储,ORDER BY col DESC 能走索引。
加分点:提到联合索引混合方向的场景。
题目 18:什么是隐藏索引?
考点:8.0 新特性。
参考答案:invisible index 存在但优化器不用。用来软删除索引观察影响,没影响再真删。
加分点:提到它解决了"删索引误删"的风险。
题目 19:什么是直方图?
考点:8.0 统计信息。
参考答案:对列的数据分布建直方图,优化器知道某列值的分布不均匀,选对执行计划。特别是非索引列。
加分点:提到 ANALYZE TABLE UPDATE HISTOGRAM。
题目 20:什么是 hash join?
考点:8.0 优化器。
参考答案:8.0.18 后无索引的等值 JOIN 用 hash join,构建哈希表后探测,比嵌套循环快。
加分点:提到它在内存够时才用,内存不够退化为磁盘。
6 加分题汇总表
| 题号 | 题目 | 所属模块 | 加分度 |
|---|---|---|---|
| 1 | 页为什么 16K | 存储架构 | 高 |
| 2 | change buffer 缓存什么 | 写优化 | 高 |
| 3 | 预读机制 | 读优化 | 中 |
| 4 | doublewrite | 崩溃恢复 | 高 |
| 5 | 事务 ID 分配 | MVCC | 中 |
| 6 | purge 线程 | MVCC 清理 | 高 |
| 7 | 自适应哈希 | 自动优化 | 中 |
| 8 | 插入意图锁 | 间隙锁 | 中 |
| 9 | semi-consistent read | 锁读 | 低 |
| 10 | MDL 锁 | 表锁 | 高 |
| 11 | 表空间加密 | 安全 | 低 |
| 12 | redo group commit | 日志 | 高 |
| 13 | 半同步复制损失 | 高可用 | 中 |
| 14 | GTID transaction set | 复制 | 中 |
| 15 | MHA 二次切换 | 高可用 | 低 |
| 16 | InnoDB 数据字典表 | 8.0 架构 | 中 |
| 17 | 降序索引 | 8.0 新特性 | 中 |
| 18 | 隐藏索引 | 8.0 新特性 | 高 |
| 19 | 直方图 | 8.0 统计 | 中 |
| 20 | hash join | 8.0 优化器 | 中 |
7 自测练习
自测 1:change buffer 为什么不能缓存唯一索引?
<details>
<summary>参考答案</summary>
唯一索引要校验唯一性,必须立即读盘检查有没有重复值,不能像普通二级索引那样先缓存后合并。所以 change buffer 只对非唯一二级索引生效。
</details>
自测 2:MDl 锁为什么会阻塞 DDL?
<details>
<summary>参考答案</summary>
查询访问表时加共享 MDl,DDL 要加排他 MDl。如果有长事务一直持有共享 MDl,DDl 就要排队等,后面的查询也被堵住。这是生产常见的"DDL 卡死"原因。
</details>
自测 3:purge 线程跟不上会怎样?
<details>
<summary>参考答案</summary>
undo log 旧版本不被清理,回滚段膨胀,查询要遍历更长的版本链,变慢。监控 purge lag。
</details>
练习 1:从这 20 题里挑 5 个你最不熟的,回到对应章节深入理解。
7.1 冷门知识深入讲解
下面把前面 20 道题里最容易被追问的几个点展开讲。
深入一:为什么 8.0 默认页还是 16K?
InnoDB 页大小从 4K 到 64K 可选,默认 16K。选 16K 是因为它平衡了点查和范围查:点查只要一页,16K 一次 IO 读够;范围查连续读,16K 比 4K 少读一半页。机械时代对齐扇区,SSD 时代对齐块。8.0 支持启动时用 innodb_page_size 改,但改了要重建实例。
深入二:change buffer 的合并时机
change buffer 里的二级索引写操作,什么时候真正写盘?三个时机:一是这页被读到缓冲池时合并;二是后台线程定期 merge;三是库干净关闭时。如果 change buffer 太大,合并时会造成 IO 抖动。
深入三:purge lag 怎么看
Purge lag 是 undo log 清理滞后的指标。如果有长事务一直持有读视图,purge 不能清理那个视图之后的 undo,导致 undo 表空间膨胀。监控 SHOW STATUS LIKE 'Innodb_undo%'。
深入四:MDL 锁排队怎么破
生产常见"一条 DDL 卡住整个库":长事务持共享 MDL,DDL 排队,后面所有新查询也排队。解法是 kill 那个长事务,或者用 pt-online-schema-change 做在线 DDL。
深入五:半同步复制的超时降级
半同步复制配置了 rpl_semi_sync_master_timeout,从库超时没确认,主库自动降级为异步复制,保证写入不阻塞。降级后从库追上来不会自动切回半同步,需要手动或等重启。
7.2 冷门知识速查表
| 知识点 | 一句话 |
|---|---|
| 页大小 | 默认 16K,可配 4K~64K |
| change buffer | 只缓存非唯一二级索引写 |
| 预读 | 顺序读多了自动预读下一区 |
| doublewrite | 脏页先写共享区再写真实位置 |
| purge 线程 | 清理旧版本 undo |
| 自适应哈希 | 热点页自动建哈希索引 |
| 插入意图锁 | 插入前加的间隙锁 |
| semi-consistent read | 更新时读最新版本再判断 |
| MDL 锁 | 表级元数据锁防 DDL 冲突 |
| 表空间加密 | 落盘密文内存明文 |
| redo 组提交 | 多个事务合并一次 fsync |
| 半同步降级 | 超时自动转异步 |
| GTID set | 从库对比缺哪些事务 |
| MHA | 主库宕机自动切从库 |
| 数据字典 | 8.0 元数据事务化 |
| 降序索引 | 8.0 真正降序存储 |
| 隐藏索引 | 存在但优化器不用 |
| 直方图 | 列数据分布统计 |
| hash join | 无索引等值 JOIN 的哈希算法 |
| 持久化自增 | 8.0 重启不跳号 |
7.3 怎么复习这些冷门题
冷门题不用全背,记住"这个点存在"即可。面试时被问到,能说出"我记得有个 XX 机制,大概是做 YY 的"就够了。下面这张表给你复习优先级。
| 优先级 | 知识点 | 理由 |
|---|---|---|
| 必背 | doublewrite、MDL、purge | 高频追问 |
| 选背 | change buffer、组提交 | 加分项 |
| 了解 | 加密、直方图 | 知道就行 |
| 可弃 | MHA 细节、预读算法 | 太冷门 |
#### 7.4 更多冷门细节
下面再补充 10 个冷门但加分的知识点。
| 知识点 | 一句话解释 |
|---|---|
| change buffer 上限 | innodb_change_buffer_max_size 控制占缓冲池比例 |
| 页压缩 | 8.0 支持 transparent page compression |
| 表压缩 | ROW_FORMAT=COMPRESKEY 压缩 BLOB |
| innodb status | 看 InnoDB 内部运行状态 |
| undo 截断 | innodb_undo_log_truncate 自动收缩 undo |
| 临时表空间 | 磁盘临时表存放位置 |
| 排序合并 | filesort 用临时表归并排序 |
| 半连接优化 | 子查询改 semi join |
| 派生表合并 | 优化器把派生表合并到外层 |
| 条件下推 | WHERE 条件下推到存储引擎 |
#### 7.5 冷门题怎么准备
冷门题不用死记硬背。准备方法是:每个知识点记住"它是干嘛的",面试时能说出大概即可。
| 准备方法 | 做法 |
|---|---|
| 看官方文档 | 翻 InnoDB 架构章节 |
| 看性能博客 | 看大厂 DBA 博客 |
| 看源码注释 | GitHub 上 InnoDB 源码注释 |
| 实际实验 | 自己搭环境验证 |
| 面试攒题 | 把被问到的冷门题记下来 |
#### 7.6 冷门题出现频率
| 频率 | 知识点 |
|---|---|
| 高频追问 | doublewrite、MDL、purge |
| 偶尔问 | change buffer、组提交 |
| 很少问 | 加密、直方图细节 |
| 几乎不问 | 预读算法细节 |
7.7 冷门知识点完整列表
下面这张表把 MySQL 里所有值得了解的冷门点列全,共 30 条。
| 序号 | 知识点 | 一句话解释 |
|---|---|---|
| 1 | 页大小 | 默认 16K,可配 4K 到 64K |
| 2 | change buffer | 缓存非唯一二级索引写 |
| 3 | 线性预读 | 顺序读多了自动预读下一区 |
| 4 | 随机预读 | 区内页都在缓冲池就预读 |
| 5 | doublewrite | 脏页先写共享区再写真实位置 |
| 6 | purge 线程 | 清理旧版本 undo |
| 7 | 自适应哈希 | 热点页自动建哈希索引 |
| 8 | 插入意图锁 | 插入前加的间隙锁 |
| 9 | semi-consistent read | 更新时读最新版本再判断 |
| 10 | MDL 锁 | 表级元数据锁 |
| 11 | 表空间加密 | 落盘密文内存明文 |
| 12 | redo 组提交 | 多事务合并一次 fsync |
| 13 | 半同步复制 | 等从库确认再提交 |
| 14 | GTID set | 从库对比缺哪些事务 |
| 15 | MHA | 主库宕机自动切从库 |
| 16 | 数据字典 | 8.0 元数据事务化 |
| 17 | 降序索引 | 8.0 真正降序存储 |
| 18 | 隐藏索引 | 存在但优化器不用 |
| 19 | 直方图 | 列数据分布统计 |
| 20 | hash join | 无索引等值 JOIN |
| 21 | 持久化自增 | 8.0 重启不跳号 |
| 22 | 原子 DDL | DDL 事务化 |
| 23 | 并行回放 | 从库多线程重演 |
| 24 | WRITESET | 按行哈希并行回放 |
| 25 | undo 截断 | 自动收缩 undo 表空间 |
| 26 | 页压缩 | 透明页压缩 |
| 27 | 临时表空间 | 磁盘临时表位置 |
| 28 | 派生表合并 | 优化器合并派生表 |
| 29 | 条件下推 | WHERE 下推到引擎 |
| 30 | 半连接优化 | 子查询改 semi join |
7.8 冷门题复习优先级
| 优先级 | 数量 | 知识点 |
|---|---|---|
| 必背 | 5 | doublewrite、MDL、purge、change buffer、组提交 |
| 选背 | 10 | 间隙锁细分、GTID、并行回放、隐藏索引、直方图 |
| 了解 | 15 | 加密、压缩、预读、MHA 细节 |
7.9 InnoDB 内部结构速查
| 组件 | 作用 |
|---|---|
| Buffer Pool | 缓存数据页索引页 |
| Change Buffer | 缓存二级索引写 |
| Adaptive Hash Index | 热点页自动哈希 |
| Log Buffer | redo 写前缓冲 |
| 数据字典 | 元数据事务化 |
| Doublewrite | 防页部分写 |
| Insert Buffer | 老名字即 change buffer |
| Purge 系统 | 清理旧版本 |
| Undo 日志 | 回滚与 MVCC |
| Redo 日志 | 崩溃恢复 |
| Rollback Segment | undo 段 |
| Checkpoint | 脏页刷盘点 |
| LRU 链表 | Buffer Pool 淘汰 |
| Flush List | 脏页链表 |
| Page Cleaner | 刷脏线程 |
| IO Threads | 后台 IO 线程 |
| Page | 最小存储单位 16K |
| Extent | 64 个页组成区 |
| Segment | 区的集合 |
| Tablespace | 表空间 |
| Row | 行记录 |
| Field | 列 |
| Index | 索引 |
| B+Tree | 索引结构 |
| MVCC | 多版本 |
7.10 复习建议
冷门题复习不用贪多。把上面表里的高频 10 个练熟,面试够用。
7.11 冷门题补充
| 知识点 | 一句话 |
|---|---|
| innodb_page_size | 默认 16K |
| innodb_flush_method | O_DIRECT |
| innodb_io_capacity | 刷脏 IO 上限 |
| innodb_max_dirty_pages_pct | 脏页水位 |
| innodb_lru_scan_depth | LRU 扫描深度 |
| innodb_page_cleaners | 刷脏线程数 |
| innodb_read_io_threads | 读 IO 线程 |
| innodb_write_io_threads | 写 IO 线程 |
| innodb_doublewrite | 双写缓冲 |
| innodb_use_native_aio | 原生异步 IO |
| innodb_flush_neighbors | 刷邻居页 |
| innodb_adaptive_flushing | 自适应刷脏 |
| innodb_autoinc_lock_mode | 自增锁模式 |
| innodb_lock_wait_timeout | 锁等待超时 |
| innodb_deadlock_detect | 死锁检测 |
| innodb_status_output_locks | 状态输出锁 |
| innodb_buffer_pool_dump_at_shutdown | 关闭 dump |
| innodb_buffer_pool_load_at_startup | 启动恢复 |
| innodb_checksum_algorithm | 页校验 |
| innodb_log_checksums | redo 校验 |
7.12 复习建议
冷门题记住"存在"即可,不用深究。
7.13 冷门补充
| 知识点 | 一句话 |
|---|---|
| 页大小 | 16K |
| change buffer | 二级索引写缓存 |
| doublewrite | 双写 |
| purge | 清理 undo |
| 自适应哈希 | 热点哈希 |
| 插入意图锁 | 间隙锁 |
| MDL | 元数据锁 |
| 组提交 | 合并 fsync |
| GTID | 全局事务 ID |
| 并行回放 | 多线程重演 |
| 隐藏索引 | 存在不用 |
| 直方图 | 数据分布 |
| hash join | 哈希连接 |
| 持久化自增 | 不跳号 |
| 原子 DDL | 事务化 |
7.14 复习
冷门题记住存在即可。
7.15 收尾
冷门题记住存在即可。
| 优先级 | 数量 |
|---|---|
| 必背 | 5 |
| 选背 | 10 |
| 了解 | 15 |
7.16 复习方法
| 方法 | 做法 |
|---|---|
| 看文档 | 翻架构章节 |
| 看博客 | 大厂 DBA |
| 做实验 | 搭环境验证 |
7.17 结尾
20 道冷门题到此结束,记住存在即可。
7.18 冷门题相关命令
-- 查看 change buffer 状态(本示例基于 MySQL 8.0)
SHOW ENGINE INNODB STATUS;
-- 在 INSERT BUFFER AND ADAPTIVE HASH INDEX 段查看
-- 查看 purge 状态(本示例基于 MySQL 8.0)
SHOW STATUS LIKE 'Innodb_purge%';
-- 查看 MDL 锁等待(本示例基于 MySQL 8.0)
SELECT * FROM performance_schema.metadata_locks;
7.19 更多调试命令
-- 查看 MDL 锁(本示例基于 MySQL 8.0)
SELECT object_name, lock_type, lock_status
FROM performance_schema.metadata_locks;
-- 查看 InnoDB 行锁等待(本示例基于 MySQL 8.0)
SELECT * FROM performance_schema.data_lock_waits;
-- 查看 histogram 信息(本示例基于 MySQL 8.0)
SELECT histogram FROM information_schema.column_statistics
WHERE table_name = 'orders';
下一篇预告:第 86 章 新手易踩的面试表达坑
文章回复
0 条公开回复