MySQL中in查询到底走不走索引呢?

46 阅读2分钟

面试题:MySQL In 到底走不走索引_哔哩哔哩_bilibili

MySQL中in查询到底走不走索引呢?还是先说结论:有时走有时不走。那么什么情况下会走索引,什么情况下不走索引呢?经过查询网络和实验,确认以下两种情况in不会走索引:

  1. in查询的数量超过总数30%;
  2. in条件数量导致 sql 大小,超过了range_optimizer_max_mem_size的值。

下面我们来验证上述两种情况。

首先我们创建一张表testin,表中建id,username,user_nickname三个字段,其中username增加普通索引。

然后使用存储过程,存入1w条数据

delimiter ;;

create procedure setdata()

begin

declare i int;

set i = 1;

while (i <= 10000) do

insert into test_in values (i, 'a', i);

set i = i + 1;

end while;

end;;

delimiter ;;

call setdata();

一、in查询数量超过约总数30%

  1. 将其中3000条数据的user_name更新为b
update test_in set user_name='b' where id <=3000;
  1. 执行
explain select * from test_in where user_name in ('b', 'l');
  1. 我们可以看到,进行的是全表扫描

  1. 我们将user_name='b' 的数量改为2900条
update test_in set user_name='a' where id >2900;
  1. 再执行
explain select * from test_in where user_name in ('b', 'l');
  1. 此时,查询走了索引

  1. 综上,in是否走索引与查询数量所占数据总数的比例有关,大约超过30%就不会走索引。

二、in条件数量导致sql大小,超过了range_optimizer_max_mem_size的值

  1. 首先我们查询该值的默认值为8388608
show VARIABLES like '%range_optimizer_max_mem_size'

  1. 将其值设置为5000
set Session range_optimizer_max_mem_size = 5000;
  1. 执行
explain select * from test_in where user_name in ('1','2','3','4','5');
  1. 可以看到sql语句走了索引

  1. 我们把in的条件加长
explain select * from test_in where user_name in ('1','2','3','4','5','6','7','8','9','10');
  1. 可以看到变成了全表扫描

  1. 此时若将range_optimizer_max_mem_size值改为12000
set Session range_optimizer_max_mem_size = 12000;
  1. 再次执行
explain select * from test_in where user_name in ('1','2','3','4','5','6','7','8','9','10');
  1. 此时sql走了索引

  1. 综上,in条件数量导致sql大小,超过了range_optimizer_max_mem_size的值后,将不再走索引。

通过上述实验,我们在日常使用in的时候,要尽量减少in的参数,也要尽量减少大比例记录的查询。