在mysql的查询场景中,in条件是非常常用的多值匹配语法,很多开发者会疑惑in查询是否一定会使用索引,其实答案并不固定,需要结合具体的表结构、查询条件和数据情况来判断。

in查询的基本使用场景
in查询通常用于匹配某个字段的多个可能值,比如查询用户表中id为1、3、5的用户信息,基础语法如下:
-- 基础in查询示例 SELECT * FROM user WHERE id IN (1, 3, 5);
这里的id字段如果建立了普通索引或者主键索引,查询时是有可能命中索引的,但并非所有情况都会走索引。
in查询使用索引的常见情况
1. 主键索引或唯一索引的等值匹配
当in条件作用在主键字段或者唯一索引字段上,且匹配的是等值条件时,mysql通常会选择使用索引,因为主键和唯一索引的区分度极高,索引扫描的效率远高于全表扫描。
-- 主键索引的in查询,一般会走索引 EXPLAIN SELECT * FROM user WHERE id IN (1, 2, 3);
执行上述EXPLAIN语句后,如果type列显示range或者const,就说明查询使用了索引。
2. 普通索引的等值匹配且值数量较少
如果in条件作用在普通索引字段上,且in后面的值数量不多,同时表的数据量较大,mysql优化器会判断索引扫描的成本低于全表扫描,此时也会选择使用索引。
-- 普通索引字段的in查询,值数量少时会走索引 -- 假设user表的age字段建立了普通索引 EXPLAIN SELECT * FROM user WHERE age IN (18, 20, 22);
in查询不使用索引的常见情况
1. in后面的值数量过多
当in后面跟随的值数量非常多时,mysql优化器会认为全表扫描的成本更低,就会放弃使用索引。这个值的数量阈值没有固定标准,和表的数据量、索引区分度都有关系,一般当值数量超过表数据量的一定比例(比如30%)时,就可能不走索引。
-- in值数量过多时可能不走索引 EXPLAIN SELECT * FROM user WHERE id IN (1,2,3,...,1000);
2. 字段类型不匹配
如果in后面的值和字段的类型不一致,mysql会做隐式类型转换,此时索引会失效,不会使用索引。比如id是int类型,但是in条件里写的是字符串类型的值:
-- 类型不匹配,索引失效
EXPLAIN SELECT * FROM user WHERE id IN ('1', '2', '3');
3. 查询返回的数据量占全表比例过高
如果in条件匹配到的数据量占了全表数据的很大比例,比如超过一半,优化器会认为全表扫描比多次索引回表更高效,就会放弃索引。
4. 索引字段参与了函数运算
如果in条件所在的字段在查询时被函数处理,那么索引也会失效,比如对时间字段做了日期格式化后再用in匹配:
-- 索引字段参与函数运算,索引失效
-- 假设create_time是datetime类型且有索引
EXPLAIN SELECT * FROM user WHERE DATE(create_time) IN ('2024-01-01', '2024-01-02');
如何判断in查询是否使用了索引
可以通过EXPLAIN关键字来查看查询的执行计划,重点看type和key两个字段:
key字段显示的是实际使用的索引名称,如果为NULL说明没有使用索引type字段显示的是访问类型,system、const、eq_ref、ref、range都属于使用了索引的高效访问类型,ALL则表示全表扫描
-- 查看执行计划示例 EXPLAIN SELECT * FROM user WHERE id IN (1, 3, 5);
优化in查询的建议
如果想要提升in查询的性能,可以参考以下建议:
- 尽量保证in条件作用的字段类型一致,避免隐式类型转换
- 如果in后面的值数量过多,可以考虑分批查询,或者将值存入临时表后做关联查询
- 不要对索引字段做函数运算或者表达式计算
- 定期分析表的索引情况,删除不必要的冗余索引,避免优化器选错索引
总的来说,mysql中in查询是否使用索引没有绝对答案,需要结合具体的查询场景分析,通过执行计划验证索引使用情况,再做对应的优化调整即可。