数据库面试题里MySQL 索引调优是永远绕不开的高频板块。不管是校招还是社招只要简历里写了 MySQL面试官大概率会从“B树”一路追到“分页优化”聚簇索引、回表、最左前缀、索引失效、EXPLAIN、MRR、索引下推……网上很多面经内容零散背完上一题忘下一题核心原因是没有形成体系。这篇内容把数据库 mysql 索引调优常见的面试题完整盘点成 50 问分成索引基础、索引失效、EXPLAIN 分析、优化实战、进阶原理五个维度。不只是列题目每个重点问题都给了可直接用于面试的简答思路和加分点。第一篇先说清楚MySQL 为什么选 B 树、什么是回表、哪些写法会让索引失效、EXPLAIN 到底怎么看、分页排序怎么优化、线上慢 SQL 怎么排查。准备 Java 后端、测试、运维方向面试的同学或者想系统补 MySQL 索引知识的开发者建议直接收藏备用。1. 索引调优 50 问速览先建立完整知识地图面试中的“夺命连环问”表面是考知识点实际是考知识结构。我先用 5 张表把 50 问的覆盖范围列出来后续章节再按重点逐个展开。1.1 索引基础篇第 1-10 问编号面试题高频度1InnoDB 为什么选择 B 树作为索引结构极高2为什么不用红黑树、哈希表或 B 树高3聚簇索引和非聚簇索引有什么区别极高4InnoDB 二级索引的叶子节点存的是什么极高5什么是回表如何避免回表极高6覆盖索引为什么快极高7为什么建议使用自增主键UUID 主键有什么影响高8普通索引和唯一索引在查询和更新上有什么区别中9哪些列适合建索引哪些列不适合高10联合索引的字段顺序怎么定极高1.2 索引失效场景篇第 11-20 问编号面试题高频度11什么是最左前缀原则极高12在索引列上使用函数为什么会导致失效高13隐式类型转换为什么会导致失效高14字符串字段和字符集不一致会导致失效吗中15OR 查询一定不走索引吗高16LIKE 模糊查询什么时候能走索引极高17NOT IN、!、IS NULL 会走索引吗高18哪些常见写法让联合索引只命中了一部分极高19为什么优化器不一定选择索引直方图有什么用中20索引下推是什么怎么证明它生效了高1.3 EXPLAIN 与慢查询篇第 21-30 问编号面试题高频度21EXPLAIN 主要看哪些列极高22type 字段从好到差怎么排极高23key_len 怎么计算高24Extra 出现 Using filesort 说明什么高25Using temporary 说明什么中26Using index 和 Using index condition 有什么区别高27怎么判断一条 SQL 是否发生了回表高28rows 扫描行数怎么理解中29慢查询日志怎么开启和解读高30批量写入时索引对性能有哪些影响中1.4 优化实战篇第 31-40 问编号面试题高频度31LIMIT 分页 offset 很大为什么慢怎么优化极高32ORDER BY 排序怎么走索引极高33GROUP BY 分组怎么优化高34COUNT(*) 为什么慢怎么优化高35JOIN 查询怎么优化驱动表怎么选极高36大表加索引要注意什么高37为什么索引不是越多越好高38冗余索引和重复索引怎么识别清理中39如何查看表上每个索引的使用情况中40优化器选错索引怎么办中1.5 进阶原理篇第 41-50 问编号面试题高频度41什么是 MRR它解决了什么问题中42什么是索引合并 index merge中43change buffer 对二级索引有什么影响中44普通索引和唯一索引在 change buffer 上有什么不同中45自适应哈希索引是什么需要人工建吗低46MVCC 下走索引查询读到的是快照还是最新数据高47当前读加锁时锁是加在索引记录上的吗高48索引基数统计不准导致选错索引怎么办中49线上大表加索引用 Online DDL 还是 gh-ost中50一条 SQL 已经有索引但还是慢接下来怎么排查极高这 50 问不是要你全部背诵。面试中 80% 的追问会落在第 5、6、10、11、16、21、22、27、31、32、35、50 这几题上。下面逐个拆解。2. 索引基础连环问从 B 树到回表这一组问题属于“一开口就知道你有没有背过面试题”的送命题回答时不要只背结论要能画出索引结构的关键差异。2.1 InnoDB 为什么选用 B 树核心答案B 树矮胖磁盘 IO 次数少叶子节点有序存储天然支持范围查询非叶子节点只存键值和指针扇出高一层能覆盖更多数据。加分点红黑树是二叉树树高约 log2N数据量千万级时树高超 20 层查询一次可能要 20 次磁盘 IO不可接受。哈希索引等值查询极快但不支持范围查询和排序。B 树非叶子节点存数据页内能存下的键值数量变少相同数据量树会更高范围查询也比 B 树复杂。B 树的叶子节点用双向链表连接SELECT * FROM t WHERE id 10这类范围扫描可以顺序遍历。回答时最好提一句“InnoDB 的数据页默认 16KB层数越少一次查询读取的页越少”这句话比单纯背“B树更矮”更有含金量。2.2 聚簇索引、非聚簇索引和回表InnoDB 的主键索引是聚簇索引叶子节点保存整行数据二级索引是非聚簇索引叶子保存索引列值和主键值。回表走二级索引查出主键值后再回聚簇索引查整行这个过程叫回表。避免回表最常见的手段是覆盖索引-- 假设 idx_user_age(age) 已存在 -- 这个查询只需要 age 和主键 id索引里都有不需要回表 SELECT id, age FROM user WHERE age BETWEEN 20 AND 30; -- 这个查询要查 name索引里没有需要回表 SELECT id, age, name FROM user WHERE age BETWEEN 20 AND 30;面试追问一般会停在“覆盖索引是不是加越多越好”。这里要说明覆盖索引本质是用空间换时间写入时每个索引都要维护索引列越多、越宽写入成本越高。所以一般只给高频查询做覆盖索引而不是所有查询都去建一个“大宽索引”。2.3 自增主键还是 UUID经常有面试题会问主键用自增还是 UUID参考答案InnoDB 聚簇索引按主键顺序组织。自增主键写入时是顺序追加页分裂概率低UUID 主键是无序的插入时可能触发大量页分裂和页重组随机 IO 变多写入性能明显下降。另外 UUID 是 16 字节自增 INT 是 4 字节、BIGINT 是 8 字节二级索引叶子节点存主键值主键越短二级索引占用的空间也越小。但要注意如果业务层需要防止订单号泄露、需要全局唯一 ID可以使用雪花算法生成的“趋势递增 ID”而不是完全随机的 UUID。2.4 联合索引的字段顺序这是索引调优面试里的重点回答要落到“索引最左前缀”和“区分度”两个维度。原则where 等值条件优先放前面把区分度高的列放在联合索引左侧可以减少扫描范围把排序或分组字段纳入联合索引可以避免 filesort如果有范围条件范围列通常放在最后。示例-- 核心查询是 SELECT * FROM order_tab WHERE user_id 12345 AND status 1 ORDER BY create_time DESC; -- 建议联合索引idx_user_status_time(user_id, status, create_time)为什么这样建user_id 是等值status 也是等值create_time 用于排序。如果只建(user_id, create_time)status 过滤就只能回表后再做而且 create_time 顺序在联合索引里会乱可能仍然 filesort。3. 索引失效的 8 种写法面试官一问一个准面试题里出现频率最高的是“什么情况下索引会失效”实际线上排查也最常用。下面这几种情况基本覆盖面试官的追问范围。3.1 最左前缀原则联合索引(a, b, c)查询条件如果只写b或只写c那这个联合索引就用不上。面试官喜欢追一句如果只查a和c部分能否走索引答案是可以。a会用于索引范围定位c只能作为回表后的过滤条件或者配合索引下推优化。这里不要回答成“走了索引就是全用上了”要分清楚“有多少列真正参与索引扫描”。3.2 在索引列上使用函数或表达式-- 失效 SELECT * FROM user WHERE DATE(create_time) 2026-01-01; -- 可优化 SELECT * FROM user WHERE create_time 2026-01-01 AND create_time 2026-01-02;MySQL 8.0 虽然支持函数索引但默认情况下对索引列套函数优化器无法直接使用原索引。更稳妥的思路是改写成范围条件或者用函数索引。3.3 隐式类型转换-- phone 字段是 varchar但参数传了数字 SELECT * FROM user WHERE phone 13800000000;MySQL 会把字符串字段转换为数字再比较索引失效。同理字符集不一致也可能导致索引列无法直接比较关联查询时两个表的 join 字段字符集不同也可能影响索引命中。线上设计表结构时关联字段尽量统一字符集。3.4 OR、LIKE、NOT IN、!简单记法OR 两边都是索引列时优化器可能使用 index merge 或两个索引分别扫描后合并只要有一边没索引就会退化全表扫描。LIKE 的规则是前缀匹配能走索引LIKE %abc不走LIKE abc%走。如果业务确实需要右侧模糊一个可行方案是把数据冗余成“倒排字段”或使用全文索引。NOT IN、!、IS NOT NULL不一定绝对失效。优化器会基于成本选择。比如IS NULL在 MySQL 里有时会走 ref关键还要看索引分布和基数。3.5 索引下推 ICP索引下推可以理解为二级索引遍历时先对索引列做过滤再回表减少回表次数。-- 联合索引 (age, name) SELECT * FROM user WHERE age 20 AND name LIKE 张%;没有 ICP 时先按 age 范围取主键再回表后用 name 过滤有 ICP 时name 的过滤直接在二级索引内完成。EXPLAIN 的 Extra 列会出现Using index condition。这是 MySQL 5.6 之后的优化面试时回答“减少了回表次数和 IO”就能拿分。4. EXPLAIN 怎么看从 type 到 Extra面试官出这道题时通常会给一条 SQL 让你读 EXECLAIN。重点不是背字段而是能在 30 秒内判断“这条 SQL 到底哪里慢”。4.1 必看的 6 个字段type、key、key_len、rows、filtered、Extra是核心。type从好到差通常排为system const eq_ref ref range index ALL。const主键或唯一索引等值查询。ref普通索引等值查询。range索引范围扫描。index整棵二级索引树扫描虽然不算全表但也不便宜。ALL全表扫描。面试时能说出“ALL 是什么时候出现、index 和 ALL 有什么区别、range 是不是一定好用”就够了。4.2 怎么判断有没有回表看 Extra。Using index直接在索引树取到所有请求列不需要回表。Using index condition用到了索引下推但可能还需要回表。如果 Extra 什么都没有且 type 是 ref 或 range大概率需要回表再取数据。key_len可以判断联合索引实际用了多少列。比如(a, b, c)三个 int 列key_len 4说明只用到akey_len 8说明用到a,b。这个知识点在面试里很加分。4.3 慢查询日志怎么开配置方法[mysqld] slow_query_log ON slow_query_log_file /var/log/mysql/slow.log long_query_time 1 log_queries_not_using_indexes ON不用记太细能在面试中说出“先开慢日志抓出真正的慢 SQL再 explain 分析”这个流程即可。5. 索引调优实战分页、排序、分组、join、count这一部分是面试官判断你“是否真的做过优化”的关键。能答出前面基础题可能只是背了面经能讲清这里的场景才有项目经验。5.1 深分页优化-- 深分页慢的写法 SELECT * FROM order_tab ORDER BY id LIMIT 100000, 20; -- 基于主键游标的写法 SELECT * FROM order_tab WHERE id 100000 ORDER BY id LIMIT 20;第二种写法适合按主键或唯一排序字段分页的场景本质上把“扫描 100020 行再扔掉 100000 行”变成“直接从 100001 行开始取 20 行”。如果 where 条件不能直接用主键可以用延迟关联SELECT o.* FROM order_tab o INNER JOIN ( SELECT id FROM order_tab ORDER BY id LIMIT 100000, 20 ) t ON o.id t.id;先只查主键再 join 回原表减少回表次数。5.2 ORDER BY 和 GROUP BYorder by 要避免 filesort核心思路是让排序字段和联合索引顺序一致并且与 where 中已确定的等值列在同一条索引路径上。示例见 2.4。group by 本质是一边分组一边排序。如果分组字段包含在联合索引内可以避免临时表。如果业务不需要排序可以加ORDER BY NULL让 MySQL 跳过排序但 MySQL 8.0 下已不再推荐依赖这个写法重点还是让 group 字段命中索引。5.3 JOIN 优化先说结论小表驱动大表join 字段必须走索引关联字段类型要一致。MySQL 执行 join 时常用 Nested Loop Join外层表每取一行都要去内层表索引里找匹配行。所以内层表的 join 字段有没有索引直接决定性能。回答模板用 EXPLAIN 看驱动表是否能用小表。给 join 条件列建立合适索引。避免把 join 的结果集做得特别大能用子查询或临时表先缩小数据再关联。如果业务对实时性要求不高可以考虑在应用层拆分查询。5.4 COUNT(*) 怎么优化面试题常见的坑InnoDB 里COUNT(*)不是 O(1) 操作因为 InnoDB 要支持 MVCC每行数据必须在事务可见性范围内统计所以不能像 MyISAM 那样直接读元数据。优化手段对实时性要求不高的场景用 information_schema.tables 的 rows 字段做近似值。用缓存或汇总表。让统计查询走辅助索引因为辅助索引一般比主键索引小扫描成本更低。6. 进阶连环追问MVCC、锁、索引统计与在线 DDL能顶到这一层基本是高级岗位或大厂面试了。这里的问题不需要背全但至少要能自洽。6.1 MVCC 和锁与索引的关系InnoDB 的普通查询是快照读走 undo log 版本链判断可见性SELECT ... FOR UPDATE、UPDATE、DELETE是当前读必须加载最新版本锁就加在索引记录上。所以面试官问“如果某条 SQL 走全表扫描加锁范围是什么”答案是“锁会作用在扫描到的所有索引记录上”也就是锁范围很大。这也是为什么生产环境非常忌讳不带 where 条件的大更新表面只 update 一行实际可能锁全表。6.2 选错索引怎么办优化器选错索引往往是因为索引基数统计不准或者样本估算有偏差。处理手段ANALYZE TABLE t;重新统计索引信息。改写 SQL引导优化器走另一个索引。使用FORCE INDEX强制指定索引但要谨慎业务数据量变化后强制索引可能反而更慢。MySQL 8.0 的直方图可以让优化器对字段值分布有更准确的判断减少选错概率。6.3 大表加索引线上大表直接ALTER TABLE可能锁表或者占用大量 IO。主流方案是 Online DDL、gh-ost 或 pt-osc。MySQL 5.6 之后 Online DDL 支持 COPY、INPLACE 和 INSTANT 算法。gh-ost 通过 binlog 同步变更不锁表适合超大表。面试能讲出“不是所有 DDL 都适合 INSTANT加字段时用 INSTANT加索引要考虑行格式和锁策略”就可以了。6.4 第 50 问已经有索引为什么还慢这是一道综合题符合“夺命连环问”的最后一环。通常从以下几个方面排查索引没有命中看 type 和 key。命中索引但区分度低扫描行数仍然很大比如性别字段上的索引。回表次数太多考虑加覆盖索引。深分页 offset 太大。大数据量下 InnoDB 缓冲池命中率低物理 IO 高。SQL 本身有排序filesort 占用临时磁盘空间。服务器层面磁盘、CPU、网络自身有问题。回答顺序建议先看慢日志定位再 explain 看执行计划再结合扫描行数和 Extra 判断是索引问题、SQL 写法问题还是数据分布问题。7. 性能验证与调优结果评估面试中如果谈到“我做过一次索引优化”最好能说出优化前后怎么验证。不要只回答“加了索引所以快了”。推荐的验证方式有三个第一执行计划对比。EXPLAIN SELECT order_id, create_time FROM order_tab WHERE user_id 12345 AND status 1;重点看优化前后的 type、rows、Extra 变化。第二会话级 profiling。SET profiling 1; SELECT * FROM order_tab WHERE user_id 12345; SHOW PROFILES; SHOW PROFILE FOR QUERY 1;可以拿到执行耗时但不要只看这一条还要结合多次执行的平均值避免冷热缓存干扰。第三索引使用情况。MySQL 提供了一张视图SELECT * FROM sys.schema_unused_indexes;这张视图能直接看到哪些索引从未被使用是清理冗余索引和重复索引的重要依据。线上清理索引前先备份、在低峰期执行并保留回滚窗口。8. 面试答题模板三种高频切入方式光记知识点不够面试官更看重你输出结论的条理性。推荐下面三个答题模板可以直接套用。8.1 线上慢 SQL 排查模板打开慢查询日志抓出具体 SQL。对慢 SQL 执行 EXPLAIN看 type、key、rows、Extra。如果没走索引分析是 SQL 写法问题、联合索引顺序问题还是根本缺索引。如果走了索引但 rows 还是很大检查回表次数、索引区分度和数据分布。改写 SQL重建或新增索引再次 explain 验证。灰度发布对比优化前后接口耗时和数据库负载。8.2 项目经验描述模板说项目时不要只讲“用了 MySQL”要讲“我做了什么”。模板系统在某个接口出现慢查询平均耗时 2 秒。我定位到一条按用户和时间范围查询订单的 SQL通过 EXPLAIN 发现没有命中索引且存在深分页问题。我重新设计了联合索引并把分页改成主键游标方式同时把一个高频查询改成覆盖索引。上线后接口耗时从 2000ms 降到了 80ms数据库 CPU 使用率下降约 20%。这样表达有数据、有方法、有验证闭环。8.3 概念题“解释覆盖索引”模板先解释原理二级索引叶子节点包含索引列和主键选出来的列全在索引中不用再回表。再举一个例子SELECT id, age FROM t WHERE age 20age 有索引id 是主键全从二级索引拿。最后补一句代价增加索引宽度的代价是写放大和存储空间上升所以只给核心高频查询做覆盖索引。9. 总结这 50 问该怎么用MySQL 索引调优不是背题而是理解数据存储和查询路径。50 问里最值得先吃透的是B 树结构、聚簇索引与回表、最左前缀、索引失效、EXPLAIN 的 type 和 Extra、深分页优化、order by / join / count 场景、线上慢 SQL 排查模板。把这些连成一条线面试时无论从哪里切入都能接到下一个问题。最容易踩的坑是只背结论比如“函数会导致索引失效”但说不清楚为什么也不知道 MySQL 8.0 的函数索引是另一个方案。建议按本文顺序先画一张索引结构图再亲手执行一次 EXPLAIN最后在测试库模拟一条慢 SQL 做完整优化。这一步做完那些看起来“夺命”的连环问其实只是同一条知识链上的不同节点。