摘要

IN 一定走索引吗?那当然了,不走索引还能全部扫描吗?好像之前有看到过什么Exist,IN走不走索引的讨论。但是好像看的太久了,又忘记了。哈哈,如果你也忘记了MySQL中IN是如何查询的,就来复习下吧。

问题

问题要从之前的统计店铺数关注人数说起

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分析

那么现在问题来了,为什么这个查询扫描行数/返回行数比例这么大呢。

那么就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的查询个数

关注公众号【方丈的寺院】,第一时间收到文章的更新,与方丈一起开始技术修行之路

SQL IN 一定走索引吗?的更多相关文章

  1. sql查询未走索引问题分析之查询数据量过大

    前因: 客户咨询,有一个业务sql(代表经常被执行且重要),全表扫描在系统占用资源很高(通过ash报告查询得到信息) 思路: 1.找到sql_text,sql_id 2.查看执行计划 3.查询sql涉 ...

  2. 以通配符(%)开始的like字符串,走索引

    在对oracle的SQL优化过程中经常会遇到[like'%abc']破坏索引的问题,但是如果真有此类需求,该如何在不破坏索引的基础上进行查询呢. [sql] view plain copy sys@m ...

  3. 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了

    今天收到运营同学的一个 SQL,有点复杂,尤其是这个 SQL explain 都很长时间执行不出来,于是我们后台团队帮忙解决这个 SQL 问题,却正好发现了一个隐藏很深的线上问题. select a. ...

  4. SQL Server-聚焦过滤索引提高查询性能(十)

    前言 这一节我们还是继续讲讲索引知识,前面我们讲了聚集索引.非聚集索引以及覆盖索引等,在这其中还有一个过滤索引,通过索引过滤我们也能提高查询性能,简短的内容,深入的理解,Always to revie ...

  5. Sql Server优化之索引提示----我们为什么需要查询提示,Sql Server默认情况下优化策略选择的不足

    环境: Sql Server2012 SP3企业版,Windows Server2008 标准版 问题由来: 最近在做DB优化的时候,发现一个存储过程有非常严重的性能问题, 由于整个SP整体逻辑是一个 ...

  6. mysql中关于关联索引的问题——对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引?

    情况描述:在MySQL的user表中,对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引? 根据查询字段的位置不同来决定,如查询a,     a,b    a,b, ...

  7. SQL Server 优化---为什么索引视图(物化视图)需要with(noexpand)强制查询提示

    本文出处:http://www.cnblogs.com/wy123/p/6694933.html 第一次通过索引视图优化SQL语句,以及遇到的一些问题,记录一下. 语句分析 最近开发递交过来一个查询统 ...

  8. MySQL实现强制查询走索引和强制查询不缓存

    0.表结构如下:(包含两个索引) Create Table: CREATE TABLE `user` ( `userID` ) NOT NULL, `userCode` ) DEFAULT NULL, ...

  9. SQL Server-聚焦过滤索引提高查询性能

    前言 这一节我们还是继续讲讲索引知识,前面我们讲了聚集索引.非聚集索引以及覆盖索引等,在这其中还有一个过滤索引,通过索引过滤我们也能提高查询性能,简短的内容,深入的理解,Always to revie ...

随机推荐

  1. 第1篇Scrum冲刺博客

    目录 第1篇Scrum冲刺博客 各个成员在 Alpha 阶段认领的任务 各个成员的任务安排 整个项目预期的任务量 敏捷开发前的感想 团队期望 第1篇Scrum冲刺博客 各个成员在 Alpha 阶段认领 ...

  2. Visual Studio 2019尝鲜----新建空项目体验

    等待一个中午的时间终于下载安装完成,vs版本Enterprise 2019  16.0.4 官方可直接下载安装引导程序:  https://visualstudio.microsoft.com/zh- ...

  3. 用for循环数组去重

    <script> var arr=["a","e","w","f","a"," ...

  4. pandas - groupby 深入及数据清洗案例

    import pandas as pd import numpy as np 分割-apply-聚合 大数据的MapReduce The most general-purpose GroupBy me ...

  5. JMETER 使用随机变量

    使用场景 在发起流程时,我们需要模拟实际情况,不同的用户可以产生不一样数量的流程实例,因此我们可以使用随机变量还进行模拟. 随机变量实例 1.添加一个循环计数器 2.添加一个循环 循环次数是根据随机变 ...

  6. [linux] 多进程和多线程

    1.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段.堆栈段和数据段,这是一种”昂贵”的多任务工作方式.2.而运行于一个进程中的多个线程,它们彼此之间使 ...

  7. linux 网站目录权限设置

    Linux下Apache网站目录读写权限的设置 网站目录文件权限的设置对网站的安全至关重要,下面简单介绍网站目录文件权限的基本设定. 我们假设http服务器运行的用户和用户组是www,网站用户为cen ...

  8. 201871010136 -赵艳强《面向对象程序设计(java)》第十六周学习总结

    201871010136-赵艳强<面向对象程序设计(java)>第十六周学习总结   项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>https://www.cnbl ...

  9. 201871010111-刘佳华《面向对象程序设计(java)》第四周学习总结

    201871010111-刘佳华<面向对象程序设计(java)>第四周学习总结 实验时间 2019-9-20 第一部分:总结第四章理论知识 4.1:类与对象的概念. 类:类是构造对象的模板 ...

  10. MySql5.7InnoDB全文索引(针对中文搜索)

    1.ngram and MeCab full-text parser plugins 全文检索在MySQL里面很早就支持了,只不过一直以来只支持英文.缘由是他从来都使用空格来作为分词的分隔符,而对于中 ...