1. 程式人生 > >SQL IN 一定走索引嗎?

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

關注公眾號【方丈的寺院】,第一時間收到文章的更新,與方丈一起開始技術修行之路

相關推薦

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 (