
MySQL 索引面试通俗总结一、什么是索引通俗理解索引就像一本书的目录。一本书有 1000 页你想找“事务”相关内容没有目录从第一页逐页翻这叫全表扫描。有目录先找到“事务在第 500 页”再直接翻过去这叫使用索引查询。所以索引本质上是帮助 MySQL 快速找到数据的一种数据结构是一种用空间换时间的设计。索引会额外占用磁盘空间而且新增、修改、删除数据时也要同步维护索引。面试回答MySQL 索引是一种帮助存储引擎快速查找数据的数据结构可以理解为数据库表的目录。没有索引时MySQL 可能需要逐行扫描有索引后可以快速定位数据。不过索引需要占用空间也会增加增删改时的维护成本所以索引并不是越多越好。二、索引有哪些分类面试中最常问的分类有四种。1. 按数据结构分类BTree 索引Hash 索引Full-Text 全文索引InnoDB 最常用的是BTree 索引。2. 按物理存储分类聚簇索引也叫主键索引二级索引也叫辅助索引、非聚簇索引3. 按字段特性分类主键索引唯一索引普通索引前缀索引4. 按字段数量分类单列索引联合索引这些分类并不冲突。例如一个索引可以同时是BTree 索引二级索引普通索引联合索引。三、为什么 InnoDB 使用 BTree通俗理解可以把 BTree 理解成商场的多级导航第一层食品区、服装区、电器区 ↓ 第二层饮料区、零食区、粮油区 ↓ 第三层可乐、牛奶、果汁找可乐时不需要把整个商场逛一遍而是按照分类一层一层往下找。BTree 不能简单理解成二分法。二叉树一个节点通常只有两个分支而 BTree 一个节点可以有很多个分支所以它是一棵多叉树。分支越多树就越矮查找数据需要访问磁盘的次数就越少。千万级数据的 BTree 通常只需要维持在三四层左右也就是说找到一条数据通常只需要少量磁盘 I/O。BTree 的特点非叶子节点主要保存索引用来指路。叶子节点保存最终数据或主键值。叶子节点按照顺序连接适合范围查询。树比较矮可以减少磁盘 I/O。为什么不用普通二叉树二叉树每个节点只有两个分支。数据量大时树会比较高查询一条数据可能需要访问很多层磁盘 I/O 次数比较多。为什么不用 HashHash 做等值查询很快WHEREid1001但是不适合范围查询WHEREidBETWEEN1000AND2000Hash 中的数据不是按照大小顺序排列的而 BTree 的叶子节点有序连接更适合数据库常见的等值查询、范围查询和排序。面试回答InnoDB 使用 BTree主要是因为 BTree 是多叉树树的高度比较低可以减少磁盘 I/O。它的数据集中存储在叶子节点单个非叶子节点可以保存更多索引。同时叶子节点有序连接非常适合范围查询和排序。相比之下二叉树层数较高Hash 虽然等值查询快但不适合范围查询。四、什么是聚簇索引和二级索引假设有一张商品表CREATETABLEproduct(idBIGINTPRIMARYKEY,product_noVARCHAR(50),nameVARCHAR(100),priceDECIMAL(10,2),INDEXidx_product_no(product_no));聚簇索引主键id对应的索引就是聚簇索引。它的叶子节点保存的是id product_no name price 其他完整数据可以理解为主键目录后面直接放着完整档案。二级索引product_no对应的是二级索引。它的叶子节点主要保存product_no 主键id可以理解为商品编码目录只记录商品编码和档案编号完整档案还在主键目录中。InnoDB 中如果表有主键就使用主键作为聚簇索引没有主键时会尝试选择不允许为 NULL 的唯一列如果仍然没有InnoDB 会生成隐藏的聚簇索引键。面试回答InnoDB 的主键索引属于聚簇索引叶子节点保存完整行数据。普通索引属于二级索引叶子节点保存索引字段和对应的主键值。因此通过二级索引查询完整数据时可能还需要根据主键再次查询聚簇索引。五、什么是回表执行SELECT*FROMproductWHEREproduct_noP1001;查询过程先查询 product_no 二级索引 ↓ 找到对应的主键 id ↓ 再根据 id 查询主键索引 ↓ 获得完整商品数据查了两棵 BTree这个过程就叫回表。通俗理解你先在“小区住户姓名目录”中查到张三住在 3 栋 502然后再去 3 栋 502 找张三。第一次查目录第二次找完整信息这就是回表。面试回答回表是指通过二级索引查询时先在二级索引中找到主键值再根据主键值去聚簇索引中查询完整行数据。因为查询了两次 BTree所以回表次数过多会增加磁盘 I/O。六、什么是覆盖索引执行SELECTid,product_noFROMproductWHEREproduct_noP1001;二级索引中本来就保存了product_no id查询需要的数据已经全部存在于二级索引中因此不需要再查询主键索引。这就叫覆盖索引。通俗理解你问物业张三住在哪一栋哪一户姓名目录里已经写了“3 栋 502”物业直接回答不需要再去张三家确认。面试回答覆盖索引是指查询需要的所有字段都能直接从索引中获取不需要再回到聚簇索引查询完整数据。覆盖索引可以减少回表次数和磁盘 I/O。执行计划的 Extra 中出现Using index一般说明使用了覆盖索引。七、什么是联合索引例如建立CREATEINDEXidx_status_create_timeONorders(status,create_time);这就是联合索引。联合索引不是分别创建两个独立目录而是按照多个字段共同排序先按照 status 排序 status 相同时再按照 create_time 排序例如待支付 2026-07-01 2026-07-02 2026-07-03 已支付 2026-07-01 2026-07-02八、什么是最左匹配原则假设存在联合索引(a, b, c)它的排序方式是先按 a 排序 a 相同时按 b 排序 a、b 都相同时按 c 排序以下查询通常可以使用联合索引WHEREa1;WHEREa1ANDb2;WHEREa1ANDb2ANDc3;以下查询无法正常利用这个联合索引的最左部分WHEREb2;WHEREc3;WHEREb2ANDc3;通俗理解假设一本电话簿按照省份 → 城市 → 姓名进行排序。你知道省份就可以快速缩小范围湖南省你知道省份和城市更容易查湖南省 → 长沙市但你只知道姓名张三因为整本目录不是先按照姓名排序所以很难直接定位。联合索引需要从最左边字段开始匹配本质原因是后面的字段只在前面字段值相同的情况下才局部有序。特别注意WHERE条件中的书写顺序通常不是关键。下面两条 SQL 一般没有本质区别WHEREa1ANDb2;WHEREb2ANDa1;MySQL 优化器通常会调整条件关键是联合索引中是否包含最左边的字段。面试回答联合索引遵循最左匹配原则因为联合索引首先按照第一个字段排序第一个字段相同时才按照第二个字段排序。因此只有从联合索引最左边的字段开始查询才能利用索引的有序性快速定位数据。九、联合索引遇到范围查询怎么办假设有联合索引(a, b)查询WHEREa1ANDb2;通常a可以用于确定索引扫描范围但进入a 1的大范围后b在整个范围中不再保持全局有序因此b通常不能继续用于缩小索引扫描区间。可以先记住面试常见结论联合索引向右匹配时遇到、这类范围条件后面的字段通常不能继续用于确定索引扫描范围。但小林文章中也特别说明、、BETWEEN、LIKE 前缀%在部分情况下仍可能继续使用后面的联合索引字段最终应结合 MySQL 版本和EXPLAIN的key_len判断。面试时不需要一开始讲得特别复杂可以先回答范围查询字段本身可以使用索引但范围查询之后的字段是否还能继续参与索引定位需要结合具体运算符和执行计划判断。十、什么是索引下推假设有联合索引(name, age)查询SELECT*FROMuserWHEREnameLIKE郭%ANDage25;没有索引下推MySQL 先根据name找到一批主键然后全部回表拿到完整数据后再判断age 25。查索引 → 回表 → 判断年龄 查索引 → 回表 → 判断年龄 查索引 → 回表 → 判断年龄有索引下推因为二级索引中已经存在age所以 MySQL 可以先在索引中判断年龄。查索引 ↓ 先过滤掉年龄不是25岁的记录 ↓ 只把满足条件的数据回表索引下推的作用就是尽量在二级索引内部提前过滤数据减少回表次数。执行计划 Extra 出现Using index condition通常表示使用了索引下推。十一、什么时候应该创建索引适合创建索引的字段有唯一性要求的字段例如订单号、商品编码。经常出现在WHERE条件中的字段。经常用于JOIN关联的字段。经常用于ORDER BY的字段。经常用于GROUP BY的字段。多个字段经常一起查询时可以考虑联合索引。例如订单查询SELECTid,order_no,status,create_timeFROMordersWHEREuser_id1001ANDstatus1ORDERBYcreate_timeDESC;可以根据实际查询考虑CREATEINDEXidx_user_status_timeONorders(user_id,status,create_time);索引不仅能用于筛选数据也可以利用自身的有序性帮助排序。十二、什么时候不建议创建索引1. 数据量特别少表里只有几十条数据全表扫描可能更快。2. 字段重复值很多例如性别字段男、女通过索引查出全表接近一半的数据意义不大。3. 很少用于查询的字段如果字段不用于WHERE、ORDER BY、GROUP BY和关联查询建立索引价值不大。4. 经常发生修改的字段每次修改索引字段都需要维护 BTree。例如用户余额经常发生变化一般不能只因为“可能查询余额”就随便给余额建立索引。索引会占用空间并降低增删改性能。十三、为什么主键推荐自增自增主键1、2、3、4、5新增数据时通常直接追加到后面1、2、3、4、5、6不需要频繁移动原有数据。随机主键原来1、3、5、9突然插入7需要插入到中间。如果数据页已经满了可能发生页分裂原来一个数据页 ↓ 拆成两个数据页 ↓ 移动部分数据页分裂会增加额外开销也可能导致空间利用率降低。所以在没有特殊业务要求时InnoDB 一般建议使用较短的自增主键。主键越短二级索引占用的空间通常也越小因为二级索引叶子节点需要保存主键值。面试回答InnoDB 的数据按照主键顺序存放。使用自增主键时新数据通常顺序追加可以减少数据移动和页分裂。如果使用随机主键数据可能插入到已有数据页中间增加页分裂和空间碎片。另外二级索引会保存主键值所以主键长度也不宜过大。十四、常见索引失效场景1. 左模糊查询WHEREnameLIKE%郭;2. 左右模糊查询WHEREnameLIKE%郭%;索引是从字符串左边开始排序的不知道开头是什么就很难快速定位。下面这种前缀匹配通常可以使用索引WHEREnameLIKE郭%;3. 对索引字段进行计算WHEREage126;可以改成WHEREage25;4. 对索引字段使用函数WHEREYEAR(create_time)2026;可以考虑改成范围查询WHEREcreate_time2026-01-01ANDcreate_time2027-01-01;5. 隐式类型转换字段是字符串phoneVARCHAR(20)错误写法WHEREphone13800138000;更合理WHEREphone13800138000;6. 不符合联合索引最左匹配有索引(user_id, status, create_time)只查询WHEREstatus1;通常无法有效使用该联合索引的最左部分。7. OR 两边有一边没有索引WHEREuser_id1001ORremark测试;如果user_id有索引而remark没有索引优化器可能放弃索引选择全表扫描。需要注意“存在这些写法”不代表百分之百不使用索引最终是否使用索引应通过EXPLAIN验证。十五、如何判断 SQL 是否使用了索引使用EXPLAINSELECT*FROMordersWHEREorder_no202607280001;重点看以下字段。possible_keys可能使用的索引。key实际使用的索引。如果key NULL通常表示没有使用索引。key_lenMySQL 实际使用了联合索引中的多少内容。rows预计需要扫描多少行。一般来说扫描行数越少越好。type数据访问方式。常见效率大致从差到好ALL → index → range → ref → eq_ref → const重点记忆ALL全表扫描需要重点关注。index扫描整个索引。range索引范围查询。ref使用普通索引查找。eq_ref多表关联时使用主键或唯一索引。const通过主键或唯一索引查询一条确定记录。Extra需要重点关注Using filesort表示不能直接利用索引完成排序需要额外排序。Using temporary表示使用了临时表经常出现在复杂排序或分组中。Using index表示使用了覆盖索引不需要回表。Using index condition表示使用了索引下推。面试高频问答速记1. 索引是什么索引是帮助 MySQL 快速定位数据的数据结构可以理解为书的目录。它通过额外的存储空间提高查询效率但也会增加增删改的维护成本。2. 为什么使用 BTreeBTree 是多叉树树高比较低可以减少磁盘 I/O数据集中在叶子节点叶子节点有序连接适合范围查询和排序。3. 聚簇索引和二级索引有什么区别聚簇索引的叶子节点保存完整行数据二级索引的叶子节点保存索引字段和主键值。一张 InnoDB 表只有一个聚簇索引但可以有多个二级索引。4. 什么是回表先通过二级索引找到主键再根据主键去聚簇索引查询完整数据这个过程叫回表。5. 什么是覆盖索引查询需要的字段都包含在索引中可以直接从索引获得结果不需要回表。6. 什么是最左匹配原则联合索引按照从左到右的字段顺序排序查询通常需要从最左边字段开始匹配才能充分利用索引的有序性。7. 什么是索引下推在遍历二级索引时先利用索引中的其他字段过滤数据减少不必要的回表次数。8. 索引是不是越多越好不是。索引会占用磁盘空间并且新增、修改、删除数据时需要维护索引会降低写入性能。9. 为什么推荐自增主键自增主键通常是顺序插入可以减少数据移动和页分裂同时主键较短也可以减少二级索引占用的空间。10. 如何排查索引有没有生效使用 EXPLAIN重点查看 type、key、key_len、rows 和 Extra判断是否使用索引、扫描多少行以及是否发生额外排序、临时表和回表。一句话记忆索引 目录 BTree 多层有序目录 主键索引 目录后面直接放完整档案 二级索引 目录里保存主键编号 回表 先查普通目录再查主键档案 覆盖索引 普通目录里已经有完整答案 联合索引 多个字段组成一个有顺序的目录 最左匹配 必须从目录最左边开始查 索引下推 回表前先在目录中过滤 EXPLAIN 检查 MySQL 到底怎么查数据项目面试表达在订单表中我通常会根据实际查询场景设计索引。例如订单号具有唯一性可以建立唯一索引用户经常按照用户 ID、订单状态和创建时间查询订单可以考虑建立(user_id, status, create_time)联合索引。同时避免直接使用SELECT *尽量通过覆盖索引减少回表。SQL 上线前会使用 EXPLAIN 检查实际使用的索引、扫描行数以及是否出现Using filesort或Using temporary。