zoukankan      html  css  js  c++  java
  • SQL IN 一定走索引吗?

    摘要

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

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

  • 相关阅读:
    leetcode 350. Intersection of Two Arrays II
    leetcode 278. First Bad Version
    leetcode 34. Find First and Last Position of Element in Sorted Array
    leetcode 54. Spiral Matrix
    leetcode 59. Spiral Matrix II
    leetcode 44. Wildcard Matching
    leetcode 10. Regular Expression Matching(正则表达式匹配)
    leetcode 174. Dungeon Game (地下城游戏)
    leetcode 36. Valid Sudoku
    Angular Elements
  • 原文地址:https://www.cnblogs.com/stoneFang/p/11032746.html
Copyright © 2011-2022 走看看