📖 本篇简介:前面学了那么多知识点,这一篇来一场全真模拟面试。面向初级 MySQL 工程师(1~3 年经验),按"第 1 轮基础 → 第 2 轮索引事务锁 → 第 3 轮实战排障"三轮递进,共 30 道高频题,每题都给参考答案和面试官追问。示例基于 MySQL 8.0。建议先自己答一遍,再对照参考答案,最后看追问——追问才是拉开差距的地方。
目录
- 1 本篇导读与面试说明
- 2 第 1 轮 基础概念与 SQL 语法
- 3 第 2 轮 索引事务与锁
- 4 第 3 轮 实战排障与调优
- 5 初级 MySQL 面试评分速查表
- 6 常见坑与注意事项
- 7 自测与复盘
1 本篇导读与面试说明
模拟面试分三轮,难度递增:
- 第 1 轮:基础概念与 SQL 语法,考察你基本功扎不扎实;
- 第 2 轮:索引、事务、锁,考察原理理解;
- 第 3 轮:实战排障与调优,考察你能不能解决真实问题。
初级岗位面试,重点不是问多难的架构,而是看你基础牢不牢、有没有真实动手经验。下面每题按"题目 → 参考答案 → 追问"展开,参考答案控制在要点级别,实际面试时要自己展开说。
2 第 1 轮 基础概念与 SQL 语法
题 1:MySQL 默认端口是多少?怎么登录?
参考答案:默认端口 3306。登录命令:mysql -u root -p -h 127.0.0.1,输入密码后进入交互。查看当前库 SELECT DATABASE();。
追问:-h localhost 和 -h 127.0.0.1 有区别吗?
有。localhost在 Linux 下走 Unix socket 文件,127.0.0.1走 TCP,权限配置可能不同。
题 2:char 和 varchar 有什么区别?怎么选?
参考答案:char 定长,不足补空格,适合长度固定的(如性别、手机号);varchar 变长,按实际长度存储,节省空间,适合长度不定的字符串。
追问:varchar(10) 的 10 代表什么?
代表最多 10 个字符(不是字节),utf8mb4 下一个中文算 1 个字符。
题 3:DELETE、TRUNCATE、DROP 区别?
参考答案:
-- DELETE:逐行删,可带 WHERE,可回滚,慢
DELETE FROM orders WHERE status = 0;
-- TRUNCATE:清空整表,不可回滚(DDL),快,自增归零
TRUNCATE TABLE orders;
-- DROP:连表结构一起删
DROP TABLE orders;
追问:为什么 TRUNCATE 比 DELETE 快?
TRUNCATE 是直接 DROP 重建表,不逐行删、不记大量 undo;DELETE 要逐行删并写日志。
题 4:WHERE 和 HAVING 区别?
参考答案:WHERE 在分组前过滤行,不能用聚合函数;HAVING 在分组后过滤分组结果,可以用聚合函数。
-- 先 WHERE 过滤,再 GROUP BY,再 HAVING 过滤分组
SELECT user_id, COUNT(*) c FROM orders
WHERE create_time > '2026-01-01' -- 分组前过滤
GROUP BY user_id
HAVING c > 5; -- 分组后过滤
追问:WHERE 里为什么不能用聚合函数?
因为 WHERE 执行时还没分组聚合,聚合结果不存在;分组后才有,所以用 HAVING。
题 5:INNER JOIN 和 LEFT JOIN 区别?
参考答案:INNER JOIN 只取两表匹配的行;LEFT JOIN 取左表全部,右表匹配不上补 NULL。
-- LEFT JOIN:所有用户,哪怕没订单也显示,订单字段补 NULL
SELECT u.name, o.order_id
FROM users u LEFT JOIN orders o ON u.id = o.user_id;
追问:LEFT JOIN 后在 WHERE 里写右表条件会怎样?
会把它变成 INNER JOIN 的效果,因为 NULL 不满足条件。右表条件要写在 ON 里。
题 6:怎么给字段加注释、给表加注释?
参考答案:建表时用 COMMENT,或 ALTER 修改。
CREATE TABLE t (
id INT COMMENT '主键',
name VARCHAR(50) COMMENT '用户名'
) COMMENT='用户表';
追问:怎么查看已有表的注释?
SHOW FULL COLUMNS FROM t; 看 Comment 列,或看 information_schema。题 7:NULL 在查询里要注意什么?
参考答案:NULL 不等于任何值(包括 NULL 自己),= NULL 永远查不到,要用 IS NULL;聚合函数会忽略 NULL。
-- 错误:永远查不到
SELECT * FROM t WHERE name = NULL;
-- 正确
SELECT * FROM t WHERE name IS NULL;
追问:COUNT(*) 和 COUNT(列) 区别?
COUNT(*) 数所有行;COUNT(列) 会忽略该列为 NULL 的行。
题 8:怎么去重?DISTINCT 和 GROUP BY 区别?
参考答案:都能去重。DISTINCT 对整行去重;GROUP BY 可以配合聚合。简单去重用 DISTINCT,要分组统计用 GROUP BY。
SELECT DISTINCT user_id FROM orders; -- 去重
SELECT user_id, COUNT(*) FROM orders GROUP BY user_id; -- 分组统计
追问:大表上 DISTINCT 为什么慢?
要排序或临时表去重,数据量大时走磁盘临时表,慢。
题 9:LIMIT 分页怎么用?深分页为什么慢?
参考答案:LIMIT offset, size。offset 越大越慢,因为要扫描 offset+size 行再丢掉前 offset。
-- 第 20 页,每页 10 条:要扫 200+10 行
SELECT * FROM orders ORDER BY id LIMIT 200, 10;
追问:怎么优化深分页?
用游标:WHERE id > 上一页最后id LIMIT 10,避免大 offset。题 10:IFNULL、COALESCE 是干嘛的?
参考答案:处理 NULL 值,把 NULL 替换成默认值。
-- score 为 NULL 时显示 0
SELECT name, IFNULL(score, 0) FROM students;
-- COALESCE 支持多个参数,返回第一个非 NULL 值
SELECT COALESCE(nickname, real_name, '匿名') FROM users;
追问:为什么业务里要少用 NULL?
NULL 处理麻烦(各种函数、比较都要特判),建议字段定义时给默认值而非 NULL。
3 第 2 轮 索引事务与锁
题 11:索引是什么?为什么能加快查询?
参考答案:索引是类似书目录的数据结构(InnoDB 用 B+ 树),不用全表扫描就能定位数据,把 O(n) 扫描变成 O(log n) 查找。
-- 给 user_id 加索引,按 user_id 查就走 B+ 树
ALTER TABLE orders ADD INDEX idx_uid (user_id);
追问:索引是不是越多越好?
不是。索引占空间,且每次写入都要维护索引,索引越多写入越慢。
题 12:B+ 树索引和哈希索引区别?
参考答案:B+ 树支持范围查询和排序;哈希只支持等值查询,O(1) 但不支持范围。InnoDB 主力是 B+ 树。
追问:为什么 InnoDB 选 B+ 树不选哈希?
业务大量是范围查询和排序,B+ 树有序天然支持;哈希处理不了范围。
题 13:什么是聚簇索引和二级索引?
参考答案:聚簇索引(主键)的叶子节点存整行数据;二级索引叶子节点存主键值,查到后要回表查主键。
-- 二级索引 idx_user_id 查到 user_id 对应主键,再回主键索引取整行(回表)
SELECT * FROM orders WHERE user_id = 123;
追问:什么是覆盖索引?
查询字段都在索引里,不用回表,Extra 显示 Using index,更快。
题 14:最左前缀原则是什么?
参考答案:联合索引 (a,b,c),查询必须从最左列开始才能用上。查 a、(a,b)、(a,b,c) 都行,只查 b、(b,c) 用不上。
-- 索引 (user_id, status, create_time)
-- 这个能用上:user_id 是最左
SELECT * FROM orders WHERE user_id = 1;
-- 这个用不上最左:跳过了 user_id
SELECT * FROM orders WHERE status = 1;
追问:范围查询后面的列能用索引吗?
不能。范围列之后的列索引失效,如 (a,b,c) 里 a>1 后,b、c 用不上。
题 15:事务的 ACID 是什么?
参考答案:原子性(要么全成要么全败)、一致性(数据前后一致)、隔离性(事务间互不干扰)、持久性(提交后永久保存)。
-- 转账事务:扣钱和加钱要么同时成功要么同时失败(原子性)
BEGIN;
UPDATE account SET money=money-100 WHERE id=1;
UPDATE account SET money=money+100 WHERE id=2;
COMMIT;
追问:原子性靠什么实现?
靠 undo log,回滚时把没提交的事务撤销。
题 16:四个隔离级别分别解决什么问题?
参考答案:读未提交→读提交(解决脏读)→可重复读(解决不可重复读)→串行化(解决幻读)。MySQL 默认 RR。
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 有 | 有 | 有 |
| 读提交 RC | 无 | 有 | 有 |
| 可重复读 RR | 无 | 无 | 基本无 |
| 串行化 | 无 | 无 | 无 |
追问:MySQL RR 怎么解决幻读?
靠 Next-Key Lock(间隙锁),防止别的事务在间隙插入。
题 17:MVCC 是什么?
参考答案:多版本并发控制,读操作读历史版本快照,不阻塞写、写不阻塞读,靠 undo log + 版本链实现。
追问:RC 和 RR 的 MVCC 快照区别?
RC 每次 SELECT 都生成新快照(能看到别人刚提交的);RR 只在事务开始生成一次快照(整个事务一致)。
题 18:行锁和表锁什么时候发生?
参考答案:InnoDB 默认行锁(走索引时);不走索引会锁全表;DDL 是表锁。
-- 走索引:只锁这一行
UPDATE account SET money=money-1 WHERE id=1;
-- 不走索引:扫描并锁大量行,接近表锁
UPDATE account SET status=1 WHERE name='张三';
追问:死锁是什么?
两个事务互相持有对方需要的锁,循环等待,MySQL 检测后回滚一个。
题 19:InnoDB 和 MyISAM 区别?
参考答案:InnoDB 支持事务、行锁、外键、崩溃恢复;MyISAM 只表锁、不支持事务,已淘汰。现在默认 InnoDB。
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务 | 支持 | 不支持 |
| 锁 | 行锁 | 表锁 |
| 外键 | 支持 | 不支持 |
| 崩溃恢复 | 支持 | 不支持 |
追问:为什么 InnoDB 成了默认?
需要事务和高并发,MyISAM 表锁在并发下瓶颈明显。
题 20:自增主键用完了怎么办?
参考答案:BIGINT 足够大(约 9.2×10^18),实际几乎用不完;INT(约 21 亿)可能不够,大表要直接用 BIGINT。
-- 大表主键直接用 BIGINT UNSIGNED,别用 INT
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
追问:自增主键有什么隐患?
分库分表后多库自增会冲突,要用全局唯一 ID。
4 第 3 轮 实战排障与调优
题 21:一条 SQL 很慢,你怎么排查?
参考答案:先 EXPLAIN 看执行计划,重点看 type(有没有 ALL)、key(走没走索引)、rows(扫描行数)、Extra(filesort/temporary)。
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
-- type=ALL 说明全表扫,要加索引
追问:EXPLAIN 里 type 从好到坏排一下?
const > eq_ref > ref > range > index > ALL。出现 ALL 要优化。
题 22:索引建了但没生效,可能原因?
参考答案:对索引列用函数、隐式类型转换、LIKE 前导%、违反最左前缀、优化器估算全表扫更快。
-- 函数导致失效
SELECT * FROM t WHERE DATE(create_time)='2026-10-07';
-- 改成范围
SELECT * FROM t WHERE create_time>='2026-10-07' AND create_time<'2026-10-08';
追问:怎么强制走索引?
SELECT ... FORCE INDEX (索引名) 验证。题 23:怎么开启慢查询日志?
参考答案:SET GLOBAL slow_query_log=ON; 设 long_query_time 阈值。
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 超过 1 秒记录
追问:慢日志开了怎么分析?
用 mysqldumpslow 或 pt-query-digest 按耗时聚合找 TOP N。
题 24:数据库 CPU 突然 100% 怎么办?
参考答案:先看 processlist 找跑最久的 SQL,定位是不是某条慢 SQL;能 KILL 先止血,再分析根因。
SELECT id, time, info FROM information_schema.processlist
WHERE command<>'Sleep' ORDER BY time DESC LIMIT 10;
追问:能直接 KILL 大事务吗?
可以止血,但大事务 KILL 后还要回滚,期间仍占资源。
题 25:主从同步是什么?从库有什么用?
参考答案:主库写 binlog,从库拉取回放实现数据复制。从库用来分担读压力(读写分离)、做备份、高可用切换。
-- 看从库同步状态
SHOW REPLICA STATUS\G
-- 看 Replica_IO_Running / Replica_SQL_Running 是否都 Yes
追问:主从延迟是什么?
从库回放 binlog 比主库写慢,Seconds_Behind_Master 变大,读到旧数据。
题 26:怎么备份 MySQL?
参考答案:逻辑备份用 mysqldump(导出 SQL);物理备份直接拷数据文件。生产用 xtrabackup 热备。
# 逻辑备份(本环境无 MySQL,仅示意)
mysqldump -u root -p shop > shop.sql
# 恢复
mysql -u root -p shop < shop.sql
追问:mysqldump 大表备份有什么问题?
锁表、慢。大库用物理热备 xtrabackup,不锁业务。
题 27:怎么看表有多大、索引有多大?
参考答案:查 information_schema.tables。
SELECT table_name,
ROUND(data_length/1024/1024,1) AS data_mb,
ROUND(index_length/1024/1024,1) AS index_mb
FROM information_schema.tables WHERE table_schema='shop';
追问:索引比数据还大说明什么?
索引建太多了,要清理冗余索引,拖慢写入。
题 28:什么是覆盖索引?什么是回表?
参考答案:二级索引查到主键后再去主键索引取整行叫回表;如果查询字段都在二级索引里,不用回表就是覆盖索引。
-- idx(user_id, create_time),只查这两列就是覆盖索引
SELECT user_id, create_time FROM orders WHERE user_id=1;
追问:怎么让 SELECT * 也走覆盖索引?
把需要的列都建进联合索引,别用 SELECT *。
题 29:事务里能不能做远程调用?
参考答案:强烈不建议。远程调用慢,会长时间持锁,并发下锁竞争和死锁暴涨。
# 错误:事务里发 RPC,持锁时间被网络延迟拉长
# BEGIN(); deduct(); rpc(); COMMIT();
# 正确:事务只做 DB 操作,RPC 放事务外
追问:那要保证一致性怎么办?
用本地消息表/最终一致,把远程调用移出事务。
题 30:业务报"锁等待超时",你怎么查?
参考答案:用 sys.innodb_lock_waits 看谁堵谁,找到持锁长事务,必要时 KILL。
SELECT * FROM sys.innodb_lock_waits;
-- blocking_pid 是元凶,去 innodb_trx 查它为什么占着锁
追问:锁等待和死锁区别?
死锁是互相等、MySQL 自动牺牲一个;锁等待是单方向排队,要找持锁长事务处理。
5 初级 MySQL 面试评分速查表
| 考察维度 | 及格要求 | 加分项 |
|---|---|---|
| SQL 语法 | 会写 JOIN、聚合、子查询 | 知道执行顺序、NULL 坑 |
| 索引 | 知道 B+ 树、最左前缀 | 能讲回表、覆盖索引 |
| 事务 | 说清 ACID 和隔离级别 | 能讲 MVCC 原理 |
| 锁 | 知道行锁表锁 | 能定位死锁/锁等待 |
| 排障 | 会 EXPLAIN、慢日志 | 能讲止血+根因流程 |
| 架构 | 知道主从、读写分离 | 能讲缓存、分表基本概念 |
| 常见送命题 | 标准思路 |
|---|---|
| SQL 慢怎么办 | EXPLAIN → 加索引/改写 → 验证 |
| CPU 100% 怎么办 | processlist 抓现场 → KILL 止血 → 根因 |
| 索引失效怎么办 | 函数/隐式转换/前导%/最左前缀 |
6 常见坑与注意事项
1. 只会背概念不会用命令:初级面试最忌"说得出原理,写不出 EXPLAIN"。每个知识点都要配一条实际命令。
2. 回答只说"加索引":一慢就加索引,不问是不是该归档、该读写分离,显得没经验。
3. 混淆锁等待和死锁:处理方式完全不同,要分清。
4. 不知道 NULL 坑:= NULL、COUNT(列) 这些细节,是区分背题和真懂的点。
5. 深分页只会 LIMIT offset:被问到深分页优化答不上来。
6. 不说版本:答题时注明 MySQL 8.0,显示你关注版本差异。
7 自测与复盘
自测 1:默写 EXPLAIN 的 type 字段从好到坏顺序。
参考答案:const > eq_ref > ref > range > index > ALL。
自测 2:说出索引失效的至少 4 种情况。
参考答案:列上函数、隐式类型转换、LIKE 前导%、违反最左前缀、OR 连无索引列、优化器主动放弃。
自测 3:画出 ACID 分别靠什么实现(undo log / redo log / lock / MVCC)。
参考答案:原子性 undo、持久性 redo、隔离性锁+MVCC、一致性是前三者共同保证。
自测 4:口述一次"SQL 慢"的完整排查流程。
自测要点:EXPLAIN 看 type/key/rows/Extra → 定位缺索引或写法问题 → 改写/加索引 → 验证。
自测 5:用自己的话解释"为什么回表慢,覆盖索引快"。
自测要点:能否说清二级索引存主键、要回主键索引取整行是随机 IO;覆盖索引在二级索引上就拿到全部字段,省了回表。
下一篇预告:第 28 章 模拟面试:中高级DBA架构师
文章回复
0 条公开回复