[英]Optimize SQL query
我正在嘗試優化這個慢查詢(> 2s)
SELECT COUNT(*)
FROM crmentity c, mdcalls_trans_activity_update mtu, mdcalls_trans mt
WHERE (mtu.dept = 'GUN' OR mtu.dept = 'gun') AND
mtu.trans_code = mt.trans_code AND
mt.activityid = c.crmid AND
MONTH(mtu.ts) = 2 AND
YEAR(mtu.ts) = YEAR(NOW()) AND
c.deleted = 0 AND
c.smownerid = 28
這是我使用EXPLAIN時的輸出:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE c index_merge PRIMARY,crmentity_smownerid_idx,crmentity_deleted_smownerid_idx,crmentity_smownerid_deleted_idx crmentity_smownerid_idx,crmentity_deleted_smownerid_idx 4,8 NULL 91 Using intersect(crmentity_smownerid_idx,crmentity_deleted_smownerid_idx); Using where; Using index
1 SIMPLE mt ref activityid activityid 4 pharex.c.crmid 60
1 SIMPLE mtu ref dept_idx dept_idx 5 const 1530 Using where
它使用我創建的索引(dept_idx),但是對於1,380,384條記錄的數據集運行查詢仍需要2秒多的時間。 還有另一種以最佳方式表達此查詢的方法嗎?
更新 :使用David的建議,查詢現在只有幾毫秒,而不是運行超過2秒(實際上,MySQL版本5.0上的51秒)。
WHERE
子句中最具選擇性的部分是什么? 也就是說,哪個條件從結果集中刪除了最可能的項目?
我猜這是mtu.ts
過濾器。 如果這是真的,你還應該索引mtu.ts
列並嘗試以可以使用索引的方式約束它; 例如,通過使用BETWEEN
運算符。
其他提示:
JOIN ... ON ()
將join子句直接附加到連接,這使得查詢更容易閱讀,無論是對於人類還是優化器 YEAR(NOW())
MONTH(mtu.ts)
。 這減少了大量使用指數的可能性。 mtu.dept = 'GUN' OR mtu.dept = 'gun'
; 單個UPDATE mtu SET dept = lower(dept)
和表中適當的CHECK dept = lower(dept)
將有助於避免這種瘋狂。 你能將文本字符串更改為數字嗎?
我能看到的最明顯的解決方案是更改COUNT(*)以覆蓋單個字段名稱,否則您的索引可能會無用!
作為一般原則,分析此類問題的一種好方法是理解您匹配的數據,以了解其基數。
也就是說,訂購您的查詢,以便首先發生最具選擇性的事情。 你的數據中更有可能是dept ='GUN'或者userId是28。
最后,您是否考慮過加入MT和MTU而不是過濾? 它可能會使您的查詢更快,因為您將限制需要日期比較的數據量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.