Skip to content

MySQL 8.0 面试题集锦 ​

生成时间:2026-06-07 22:38(北京时间)
覆盖主题:InnoDB架构、索引优化、事务隔离、MVCC、锁机制、SQL优化、主从复制、分库分表、窗口函数、CTE、JSON支持、性能调优


第1题:InnoDB 的多版本并发控制(MVCC)是如何工作的? ​

难度: ⭐⭐⭐

标准答案:

InnoDB 的 MVCC(Multi-Version Concurrency Control)通过 隐藏列 + undo log 实现:

  • 每行数据有两个隐藏列:DB_TRX_ID(最近修改的事务ID)和 DB_ROLL_PTR(指向 undo log 记录的指针)
  • 每次 UPDATE 时,旧数据被写入 undo log,新数据写入数据页,DB_ROLL_PTR 指向旧版本
  • 读取时,根据事务的 read view(快照)判断:若行的 DB_TRX_ID 对事务可见,或该版本已被删除,则通过 DB_ROLL_PTR 链式回溯查找可见的历史版本

关键点: READ COMMITTED 和 REPEATABLE READ 的区别在于 read view 的生成时机——前者每条 SQL 重新生成,后者事务开始时生成。


第2题:InnoDB 行锁的种类有哪些?间隙锁(Gap Lock)的作用是什么? ​

难度: ⭐⭐

标准答案:

InnoDB 行锁分为:

类型说明
记录锁(Record Lock)锁住索引记录本身
间隙锁(Gap Lock)锁住索引记录之间的间隙,防止幻读
临键锁(Next-Key Lock)记录锁 + 间隙锁的组合,REPEATABLE READ 下的默认加锁方式
插入意向锁(Insert Intention Lock)INSERT 操作在等待时获取的间隙锁,告诉其他事务"有线程正在等待插入"

间隙锁的作用: 在 RR 隔离级别下,防止其他事务在范围内插入新记录,避免幻读(Phantom Read)。

延伸思考: 间隙锁只在唯一索引的等值查询时退化(退化为记录锁),非唯一索引的等值查询和范围查询仍会加间隙锁,这是导致死锁的常见原因。


第3题:MySQL 8.0 的 CTE(公用表表达式)相比传统子查询有什么优势? ​

难度: ⭐⭐

标准答案:

CTE(Common Table Expression)分为普通 CTE 和递归 CTE:

sql
-- 普通 CTE:替代重复子查询,语义更清晰
WITH active_users AS (
  SELECT * FROM users WHERE status = 'active'
)
SELECT u.* FROM active_users u
JOIN orders o ON u.id = o.user_id;

-- 递归 CTE:替代 WITH RECURSIVE,语法更简洁
WITH RECURSIVE cte AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM cte WHERE n < 10
)
SELECT * FROM cte;

优势:

  1. 可读性更高——将复杂逻辑命名提取,主查询更简洁
  2. 可重复引用——同一 CTE 在查询中可被多次使用
  3. 递归能力更强——替代了旧的 WITH RECURSIVE 语法,支持更直观的树/层级结构查询
  4. 适合临时数据分析,无需创建临时表

第4题:REPEATABLE READ 隔离级别下,如何解决幻读问题? ​

难度: ⭐⭐⭐

标准答案:

MySQL InnoDB 在 RR 级别下通过以下机制解决幻读:

  1. MVCC 解决快照读的幻读:事务的 read view 不变,避免看到其他事务新提交的插入
  2. Next-Key Lock 解决当前读的幻读:对扫描到的索引范围加锁(记录锁 + 间隙锁),阻止其他事务在范围内插入

但存在例外: SELECT ... FOR UPDATE 和 INSERT 操作仍可能触发幻读(Next-Key Lock 仅在索引覆盖范围内生效)。极端场景可通过 LOCK IN SHARE MODE 或显式加锁(SELECT ... FOR UPDATE WHERE pk = xxx)强化控制。

延伸思考: 淘宝等高并发业务通常将隔离级别降为 READ COMMITTED,放弃间隙锁以换取并发性能,幻读通过业务层兜底。


第5题:Explain 输出中 type、key、Extra 字段有哪些重要值需要关注? ​

难度: ⭐⭐

标准答案:

type 字段(连接类型,从好到差):

system > const > eq_ref > ref > range > index > ALL
  • const:主键/唯一索引等值查询,最多返回1条记录
  • ref:非唯一索引等值查询
  • range:索引范围扫描(>, <, BETWEEN, IN, LIKE 前缀)
  • ALL:全表扫描(必须优化)

key 字段: 实际使用的索引名,NULL 表示未走索引。

Extra 字段关键值:

值含义
Using index覆盖索引,无需回表
Using index condition索引下推(ICP)
Using where需要在存储引擎层后过滤
Using filesort文件排序,需优化(加索引或改写 SQL)
Using temporary使用临时表,需优化
Using join bufferNL 连接时使用 join buffer

第6题:什么是索引下推(Index Condition Pushdown,ICP)?MySQL 8.0 有哪些新优化? ​

难度: ⭐⭐

标准答案:

ICP 原理: 在 MySQL 5.6+引入,以前存储引擎读取数据到 server 层后再过滤条件;ICP 允许将条件下推到存储引擎层,在索引遍历时直接过滤,减少回表次数。

示例: 复合索引 (name, age),查询 WHERE name = '张三' AND age > 25

  • 无 ICP:先按 name 找到所有记录,回表后再过滤 age
  • 有 ICP:存储引擎层直接用 age > 25 过滤,只回表符合条件的记录

MySQL 8.0 新增优化:

  1. 倒排索引(Inverted Index):支持 JSON_FULLTEXT() 对 JSON 字段的全文搜索
  2. 窗口函数原生支持(8.0+):无需模拟,直接使用 ROW_NUMBER()、RANK()、LAG() 等
  3. Skip Scan:优化非前缀列的选择性查询(SELECT COUNT(DISTINCT name) FROM orders 可跳过 name 列直接扫描)
  4. 函数索引:可直接对表达式建索引,如 INDEX idx (( YEAR(create_time) ))

第7题:MySQL 主从复制中,binlog 有哪三种格式?各自优缺点是什么? ​

难度: ⭐⭐

标准答案:

格式说明优点缺点
ROW记录每行数据的变化数据一致性最高,可准确同步;支持闪电崩恢复binlog 体积最大,网络传输开销高
STATEMENT记录修改数据的 SQL 语句binlog 最小,可审计;支持变量函数(如 NOW())的正确语义某些函数执行结果不确定(如 UUID()),可能导致主从不一致
MIXED混合模式,MySQL 5.7+默认正常用 STATEMENT,危险语句自动切换为 ROW行为不可预测,排查问题较复杂

建议: 金融类一致性要求高的场景用 ROW;高并发日志类场景用 STATEMENT;一般场景用 MIXED。

补充: MySQL 8.0 支持 binlog_transaction_compression,可对 binlog 事务级压缩,节省 60%~80% 传输流量。


第8题:分库分表的常见中间件有哪些?分片策略如何选择? ​

难度: ⭐⭐⭐

标准答案:

常见中间件: ShardingSphere(ShardingSphere-JDBC / ShardingSphere-Proxy)、MyCat、Vitess(Vitess 是 YouTube 开源的分布式 MySQL 方案)。

分片策略:

策略适用场景缺点
哈希分片数据分布均匀 JOIN 少扩缩容成本高(需要全量迁移)
范围分片按时间/ID顺序查询的场景热点数据集中在单个分片
一致性哈希减少扩缩容时数据迁移量实现复杂,节点不均问题

跨分片查询的解决方案:

  1. 异构索引表:按查询字段再建一张路由表
  2. ES/Hive 离线查询:将数据同步到搜索引擎
  3. 广播表:小表全量复制到各分片
  4. 分布式事务(Seata / AT 模式):保证跨库一致性

第9题:窗口函数(Window Functions)和普通聚合函数的区别是什么?请举例 ​

难度: ⭐⭐

标准答案:

普通聚合函数将多行压缩为一行,窗口函数不减少行数,每行仍然保留,同时附加聚合结果。

sql
-- 普通聚合:10行 → 1行
SELECT SUM(salary) FROM employees;

-- 窗口函数:10行 → 10行,每行都有各自的汇总值
SELECT
  name,
  dept,
  salary,
  SUM(salary) OVER (PARTITION BY dept ORDER BY hire_date) AS dept_running_total,
  AVG(salary) OVER (PARTITION BY dept) AS dept_avg,
  RANK() OVER (ORDER BY salary DESC) AS salary_rank,
  LAG(salary, 1) OVER (ORDER BY hire_date) AS prev_salary,
  salary - AVG(salary) OVER (PARTITION BY dept) AS diff_from_dept_avg
FROM employees;

常用窗口函数分类:

  • 聚合类:SUM()、AVG()、COUNT()、MAX()、MIN()
  • 排名类:ROW_NUMBER()(无并列)、RANK()(有并列)、DENSE_RANK()(无间隔)
  • 导航类:LAG()(前一行)、LEAD()(后一行)、FIRST_VALUE()、LAST_VALUE()
  • 分布类:PERCENT_RANK()、CUME_DIST()、NTILE(n)

第10题:MySQL 8.0 的 JSON 数据类型有哪些常用函数?如何利用 JSON 索引优化查询? ​

难度: ⭐⭐

标准答案:

常用 JSON 函数:

sql
-- 查询
JSON_EXTRACT(col, '$.key')       -- 提取值(MySQL 8.0 可用 col->>'$.key' 简写)
JSON_CONTAINS(col, '"value"')    -- 是否包含
JSON_SEARCH(col, 'one', '%key%')  -- 搜索

-- 创建与修改
JSON_OBJECT('name', '张三', 'age', 30)           -- 构建 JSON 对象
JSON_ARRAY('a', 'b', 'c')                        -- 构建 JSON 数组
JSON_SET(col, '$.gender', 'M')                   -- 新增/更新字段
JSON_INSERT(col, '$.addr', '北京')               -- 仅插入(不覆盖已有)
JSON_REMOVE(col, '$.temp')                       -- 删除字段
JSON_MERGE_PATCH(col1, col2)                     -- 合并(后者覆盖前者)

-- 类型转换与检查
JSON_TYPE(col)                                   -- 返回值的 JSON 类型
JSON_VALID(str)                                  -- 检查是否为合法 JSON

JSON 索引优化:

MySQL 8.0 支持表达式索引,对 JSON 字段中的某个路径建索引:

sql
-- 创建表达式索引(虚拟列 + 索引)
ALTER TABLE orders ADD COLUMN city VARCHAR(50) 
  GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(addr, '$.city'))) VIRTUAL;
CREATE INDEX idx_city ON orders(city);

-- 等价于直接索引 addr 字段的 city 路径
CREATE INDEX idx_city ON orders((JSON_EXTRACT(addr, '$.city')));

-- 查询时需保持一致才能命中索引
SELECT * FROM orders WHERE JSON_EXTRACT(addr, '$.city') = '北京';

性能建议: 频繁查询的 JSON 路径应建表达式索引;JSON 体积过大会影响性能,考虑冗余字段替代。


📚 本题库由阿虾 AI 助手自动生成 | 祝面试顺利!