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的查詢個數

關注公衆號【方丈的寺院】,第一時間收到文章的更新,與方丈一塊兒開始技術修行之路
在這裏插入圖片描述

相關文章
相關標籤/搜索