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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM