問題來源
每個機(jī)票訂單含有多個票,用符合條件的訂單List宴咧,去查詢對應(yīng)的票List胰苏。
兩張表的關(guān)聯(lián)方式是用一個特性的key關(guān)聯(lián),其中包含浪漠,代理商區(qū)分標(biāo)志,訂單號霎褐,訂單類型等址愿,是一個長度在30~50之間的varchar
遍歷list一條一條查的話,IO太多冻璃,顯然不合適响谓。我們就想到用in來實現(xiàn)批量查詢
問題發(fā)現(xiàn)
在beta測試時,庫中表里只有一個月的數(shù)據(jù)省艳,大約在1000萬左右娘纷,測試時沒有發(fā)現(xiàn)問題。
到了線上之后跋炕,發(fā)現(xiàn)查詢數(shù)據(jù)非常慢赖晶,兩萬左右的in條件,查詢起來辐烂,時間在10分鐘左右遏插,顯然出現(xiàn)了慢查詢。
針對這個問題纠修,做了幾個測試胳嘲,看了下執(zhí)行計劃,如下所示
數(shù)據(jù)量小扣草,用了索引
事實上我們看到了牛,在in語句中數(shù)據(jù)量不大的情況下,索引是有效的辰妙,不過這個數(shù)量已經(jīng)是極限了鹰祸。
下面是我的語句
explain
select *
from ticket
where order_key in ('1','2','3','4','5','6','7','8',... ,'15933');
數(shù)據(jù)量大,in使得索引失效
這里在in里面包含了三萬條數(shù)據(jù)上岗,索引實效了福荸。
這里我們首先想到,強(qiáng)制使用索引會不會有所幫助如下
explain
select *
from ticket force index (uniq_order_key_ticket_id)
where order_key in ('1','2','3','4','5','6','7','8',... ,'29999');
但是肴掷,事實上并沒有效果敬锐,這是結(jié)果
解下來我們分析一下背传,兩個問題,索引為什么會失效
這個問題需要從兩個方面入手
1.索引區(qū)分度
2.預(yù)計掃描行數(shù)
3.優(yōu)化器的選擇
先看第一個台夺,索引的區(qū)分度径玖,經(jīng)過隨機(jī)采樣,看著內(nèi)容還是很高的颤介。
show index from ticket
預(yù)計掃描行數(shù)
預(yù)計掃描行數(shù)的話梳星,如前兩圖所示,基本都走了全表掃描滚朵。
優(yōu)化器的選擇
優(yōu)化器選擇時冤灾,衡量了回表等操作,綜合考慮辕近,這里沒有辦法繼續(xù)下去了韵吨,只能問到DBA了。
有用的結(jié)論
在數(shù)據(jù)表大時移宅,索引負(fù)重較大归粉,同樣的情況下,in語句里面數(shù)據(jù)條數(shù)夠大時漏峰,索引會失效糠悼,可以通過force index嘗試一下,不過成功的可能行很小浅乔,盡量分批去查找倔喂,批次數(shù)量可配置。