簡體   English   中英

優化SQL查詢

[英]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())
  • 避免WHERE子句中所選列的功能,如MONTH(mtu.ts) 這減少了大量使用指數的可能性。
  • 規范化數據以避免套管問題,如mtu.dept = 'GUN' OR mtu.dept = 'gun' ; 單個UPDATE mtu SET dept = lower(dept)和表中適當的CHECK dept = lower(dept)將有助於避免這種瘋狂。
  1. 我會使用連接重寫查詢。 它更清晰,給予優化者更好的機會。
  2. 月(mtu.ts)= 2和年(mtu.ts)=年(現在()) - 更好地使用..和..之間的mtu.ts

你能將文本字符串更改為數字嗎?

我能看到的最明顯的解決方案是更改COUNT(*)以覆蓋單個字段名稱,否則您的索引可能會無用!

作為一般原則,分析此類問題的一種好方法是理解您匹配的數據,以了解其基數。

也就是說,訂購您的查詢,以便首先發生最具選擇性的事情。 你的數據中更有可能是dept ='GUN'或者userId是28。

最后,您是否考慮過加入MT和MTU而不是過濾? 它可能會使您的查詢更快,因為您將限制需要日期比較的數據量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM