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的檢測報告時
- 掃描行數和返回行數比例超過了100
- 使用了group_by函式,注意檢查group_by是否用到了索引
分析
首先可以確定的是,group by 的shop_id
先複習下分析查詢語句的三大要素
- 響應時間,意思很明確,不多解釋了
- 掃描行數 整個查詢過程中掃描了多少行
- 返回行數 查詢結果命中的行數
一般來說掃描行數和返回行數一樣,是最好的,但是這是理想情況,事實並非如此。關聯查詢/範圍排序查詢時都會使得掃描行數大於返回行數。一般這個比例要控制在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查詢的範圍。原因有以下幾點
- IN 的條件過多,會導致索引失效,走索引掃描
- IN 的條件過多,返回的資料會很多,可能會導致應用堆內記憶體溢位。
所以必須要控制好IN的查詢個數
關注公眾號【方丈的寺院】,第一時間收到文章的更新,與方丈一起開始技術修行之路
相關推薦
SQL IN 一定走索引嗎?
摘要 IN 一定走索引嗎?那當然了,不走索引還能全部掃描嗎?好像之前有看到過什麼Exist,IN走不走索引的討論。但是好像看的太久了,又忘記了。哈哈,如果你也忘記了MySQL中IN是如何查詢的,就來複習下吧。 問題 問題要從之前的統計店鋪數關注人數說起 SELECT shop_id, count(user_I
sql查詢未走索引問題分析之查詢數據量過大
splay 需求 函數 osi 類型 未使用 nbsp order 用戶 前因: 客戶咨詢,有一個業務sql(代表經常被執行且重要),全表掃描在系統占用資源很高(通過ash報告查詢得到信息) 思路: 1.找到sql_text,sql_id 2.查看執行計劃 3.查詢sq
mysql in 不走索引的思考
最近開發提出一個疑問,mysql 5.6版本中 in 並沒有走索引。SQL 如下格式: select a, b , c, d from T where b in ( x1, x2,x3) 反應思路: 1 . analyze tab
開發人員喜歡用的 [email protected] or @n='' 會走索引嗎?
USE tempdb GO --建立測試表,並插入 100 萬條記錄 IF OBJECT_ID('t') IS NOT NULL DROP TABLE t GO CREATE TABLE t( id
記一次sql優優化——left join不走索引問題
alt 卡住 image sql col ima cnblogs 優化 .cn sql一執行就卡住,然後就...殺進程了 看了一下表的大小 第一反應就是加索引,然後explain看了一下走什麽索引了,結果很尷尬,三個表,只走了一個索引...一群人在那糾結為毛走不了索引。
SQL Server中LIKE %search_string% 走索引查詢(Index Seek)淺析
在SQL Server的SQL優化過程中,如果遇到WHERE條件中包含LIKE '%search_string%'是一件非常頭痛的事情。這種情況下,一般要修改業務邏輯或改寫SQL才能解決SQL執行計劃走索引掃描或全表掃描的問題。最近在優化SQL語句的時候,遇到了一個很有意思的問題。某些使用LIKE
UPDATE能走索引還會鎖全表嗎
問題描述 葉師傅有次上課過程中執行UPDATE測試案例時,發現雖然WHERE條件列已有索引,有時候能利用二級索引進行更新(且只鎖定相應必要的幾行記錄),但有時候卻變成了根據主鍵進行更新,且會鎖全表。我們先來看看下面的例子。 測試表 t1 CREATE TABLE `t1` ( `c1`
sql不走索引總結(多看多記住啊)
Oracle在執行一個SQL之前,首先要分析一下語句的執行計劃,然後再按執行計劃去執行。分析語句的執行計劃的工作是 由優化器(Optimizer)來完成的。不同的情況,一條SQL可能有多種執行計劃,但在某一時點,一定只有一種執行計劃是最優的,花費時間是最少的。 相信你一定會用Pl/sql Develop
oracle sql強制走索引提高查詢效率
一般建表的時候加了縮影,使用這張表的對應欄位的時候,會走縮影,但是有時候會出現飄索引的現象;建議加上強制走索引的條件: select /*INDEX(bmq OPERATOR_CARD_MATCHE
避免寫出不走索引的SQL, MySQL
故,如果需要計算,千萬不要計算到索引列,想方設法讓其計算到表示式的另一邊去。 索引列使用了函式 同樣的道理,索引列使用了函式,一樣會導致相同的後果 SELECT `sname` FROM `stu` WHERE concat(`sname`,'abc') ='Jaskeyabc'; -- 不會使用索引,因為使
in走不走索引?可以用哪個關鍵字代替?
網上有很多人說in不走索引,事實上我經過執行計劃自己測試發現,in明明就是走索引的。看來網上也不全可信啊。後來又查了以下,發現 MySQL 4.1 以上版本的 IN 是走索引的, 但4.0及其以下版本是不走索引的。 原來是這樣,4.0以下確實是不走索引的,難怪之前有人說。可以
資料型別不一致導致的SQL不走索引
前幾天,同事發來一條SQL,說是更新操作的時候執行的很慢,我看了下,資料量也不是很大。再檢視執行計劃,發現是執行路徑錯誤導致的,可是為什麼會走錯誤的執行路徑呢?統計資訊並沒有太大的問題。在這裡模擬下: 資料準備: --1.資料準備,表一: DROP TABLE t_tes
SQL SERVER查看索引使用情況
use can png log table schema ats _id sca SELECT DISTINCT DB_NAME() AS N‘db_name‘ , E.name AS N‘schema_name‘ , O
or/in/union與索引優化
例子 表結構 全表掃描 訂單 掃描 oid tro add 分析 假設訂單業務表結構為: order(oid, date, uid, status, money, time, …) 其中: oid,訂單ID,主鍵 date,下單日期,有普通索引,管理後臺經常按照da
mybatis sql in not in的使用
col item select lis log div ots sel index xml配置 <select id="SelectAllByNotsampleNo" resultMap="BaseResultMap" parameterType="java.l
Install Local SQL In Mac OS
ext 設置 root密碼 end itblog 改密碼 操作數 com 出現 extends:http://www.cnblogs.com/maxinliang/p/3583702.html 一、安裝 到MySQL官網上http://dev.mysql.com/dow
[12]SQL IN 操作符
amp site www 微博 bsp ted tty 操作 upload [12]SQL IN 操作符 下面是選自 "Websites" 表的數據: +----+--------------+---------------------------+-------+----
SQL Server 非聚集索引的覆蓋,連接,交叉和過濾 <第二篇>
相對 col 超過 引用 保持 書簽 基本 nbsp 當我 在SQL Server中,非聚集索引其實可以看做是一個含有聚集索引的表,但相對實際的表來說,非聚集索引中所存儲的表的列數要少得多,一般就是索引列,聚集鍵(或RID)。非聚集索引僅僅包含源表中的非聚集索引的列和指
以通配符(%)開始的like字符串,走索引
and rownum plain 需求 autotrace use tab dbms ace 在對oracle的SQL優化過程中經常會遇到【like‘%abc‘】破壞索引的問題,但是如果真有此類需求,該如何在不破壞索引的基礎上進行查詢呢。 [sql] view plain
SQL Server 創建索引的 5 種方法
log htm bool 是我 大量 還在 serve src with 引自https://www.cnblogs.com/JiangLe/p/4007091.html 前期準備: create table Employee (