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掉,防止拖垮整個數據庫,致使相關應用都受到牽連。bash
該SQL執行時間耗時已經幾百ms了,必需要優化了。阿里雲對這個SQL的檢測報告時函數
- 掃描行數和返回行數比例超過了100
- 使用了group_by函數,注意檢查group_by是否用到了索引
首先能夠肯定的是,group by 的shop_id
字段確定是建了索引的,那麼掃描行數和返回行數比例爲何這麼大呢?微服務
先複習下分析查詢語句的三大要素性能
- 響應時間,意思很明確,很少解釋了
- 掃描行數 整個查詢過程當中掃描了多少行
- 返回行數 查詢結果命中的行數 通常來講掃描行數和返回行數同樣,是最好的,可是這是理想狀況,事實並不是如此。關聯查詢/範圍排序查詢時都會使得掃描行數大於返回行數。通常這個比例要控制在10如下,不然可能會有性能問題。
題外話,我一直以爲mysql explain的展現字段不如mongo的直觀。mongo索引原理同mysql同樣,有興趣的能夠看下Mongo Index分析優化
那麼如今問題來了,爲何這個查詢掃描行數/返回行數比例這麼大呢。阿里雲
那麼就explain 一下了
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的索引,沒毛病。那怎麼掃描行數/返回行數比例這麼大的。
再試一把,將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
,也就是沒有走範圍掃描,而是走的是索引掃描。
強制走索引
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查詢的範圍。緣由有如下幾點
因此必需要控制好IN的查詢個數
關注公衆號【方丈的寺院】,第一時間收到文章的更新,與方丈一塊兒開始技術修行之路