SQL IN 必定走索引吗?

摘要

IN 必定走索引吗?那固然了,不走索引还能所有扫描吗?好像以前有看到过什么Exist,IN走不走索引的讨论。可是好像看的过久了,又忘记了。哈哈,若是你也忘记了MySQL中IN是如何查询的,就来复习下吧。mysql

问题

问题要从以前的统计店铺数关注人数提及sql

SELECT shop_id, count(user_Id) as attentionNumber
FROM shop_attention
WHERE shop_id IN
<foreach collection="shopIds" item="shopId" separator="," open="(" close=")">
    #{shopId}
</foreach>
GROUP BY shopId

当时是从缓存的角度来分析如何进行优化。有兴趣看这篇微服务化后缓存怎么作数据库

将这个查询收敛,应用端作了缓存后,确实没什么大问题了。可是随着店铺关注数的增长,慢SQL开始出现了缓存

在咱们的业务中,将100ms的SQL查询定义为慢查询,须要优化的。优化不了必需要控制查询频次。同时超过5s的数据库操做会被kill掉,防止拖垮整个数据库,致使相关应用都受到牵连。函数

该SQL执行时间耗时已经几百ms了,必需要优化了。阿里云对这个SQL的检测报告时微服务

  1. 扫描行数和返回行数比例超过了100
  2. 使用了group_by函数,注意检查group_by是否用到了索引

分析

首先能够肯定的是,group by 的shop_id字段确定是建了索引的,那么扫描行数和返回行数比例为何这么大呢?性能

先复习下分析查询语句的三大要素优化

  1. 响应时间,意思很明确,很少解释了
  2. 扫描行数 整个查询过程当中扫描了多少行
  3. 返回行数 查询结果命中的行数
    通常来讲扫描行数和返回行数同样,是最好的,可是这是理想状况,事实并不是如此。关联查询/范围排序查询时都会使得扫描行数大于返回行数。通常这个比例要控制在10如下,不然可能会有性能问题。

题外话,我一直以为mysql explain的展现字段不如mongo的直观。mongo索引原理同mysql同样,有兴趣的能够看下Mongo Index分析阿里云

那么如今问题来了,为何这个查询扫描行数/返回行数比例这么大呢。.net

那么就explain 一下了

实验1

SELECT shop_id, count(user_Id) as attentionNumber
FROM shop_attention
WHERE shop_id IN(1,2,3)
GROUP BY shopId
type possible_keys key key_length ref rows Extras
range idx_shop idx_shop 8 null 16000 Using index condition

和我预想的同样,类型是range走了shopId的索引,没毛病。那怎么扫描行数/返回行数比例这么大的。

实验2

再试一把,将IN的范围增大了。

SELECT shop_id, count(user_Id) as attentionNumber
FROM shop_attention
WHERE shop_id IN(1,2,3,4,5,6,7,8,9)
GROUP BY shopId
type possible_keys key key_length ref rows Extras
index idx_shop idx_shop 8 null 303000 Using where

结果不同了,类型是index,也就是没有走范围扫描,而是走的是索引扫描。

实验3

强制走索引

SELECT shop_id, count(user_Id) as attentionNumber
FROM shop_attention force index(idx_shop)
WHERE shop_id IN(1,2,3,4,5,6,7,8,9)
GROUP BY shopId
type possible_keys key key_length ref rows Extras
range idx_shop idx_shop 8 null 29000 Using Index Condition

这时候走的是范围扫描,而不是索引扫描。可是你会发现此次的执行时间并不没有比·上一次的执行时间短

mysql对这个查询进行了优化,使其不走范围扫描。而是走的是索引扫描。那么必然会随着IN的条件愈来愈多,
扫描的行数越多,执行的时间越长。

因此这个问题的优化的办法呢,就是在应用端作切割,分批去查。每次查N个,保证每次的查询都很快。

总结

根据实际的状况,须要控制IN查询的范围。缘由有如下几点

  1. IN 的条件过多,会致使索引失效,走索引扫描
  2. IN 的条件过多,返回的数据会不少,可能会致使应用堆内内存溢出。

因此必需要控制好IN的查询个数

关注公众号【方丈的寺院】,第一时间收到文章的更新,与方丈一块儿开始技术修行之路
在这里插入图片描述

相关文章
相关标签/搜索