[英]How can I speed up MySQL query with multiple joins
這是我的問題,我正在選擇並進行多次連接以獲得正確的項目...它會提取相當數量的行,超過100,000。 當日期范圍設置為1年時,此查詢需要超過5分鍾。
我不知道是否可能,但我擔心用戶可能會將日期范圍延長至十年並使其崩潰。
誰知道我怎么能加快速度呢? 這是查詢。
SELECT DISTINCT t1.first_name, t1.last_name, t1.email
FROM table1 AS t1
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id
WHERE t1.subscribe =1
AND t1.Cdate >= $startDate
AND t1.Cdate <= $endDate
AND t5.store =2
我不是最好的mysql所以任何幫助將不勝感激!
提前致謝!
UPDATE
這是你要求的解釋
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t5 ref PRIMARY,C_store_type,C_id,C_store_type_2 C_store_type_2 1 const 101 Using temporary
1 SIMPLE t4 ref PRIMARY,P_cat P_cat 5 alphacom.t5.C_id 326 Using where
1 SIMPLE t3 ref I_pid,I_oref I_pid 4 alphacom.t4.P_id 31
1 SIMPLE t2 eq_ref O_ref,O_cid O_ref 28 alphacom.t3.I_oref 1
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 alphacom.t2.O_cid 1 Using where
我還為table5行和table4行添加了一個索引,因為它們並沒有真正改變,但是其他表每月大約有500-1000個條目......我聽說你應該為一個包含許多新條目的表添加一個索引....這是真的?
我試試以下內容:
首先,確保以下表和列上有索引(括號中的每組列應該是一個單獨的索引):
table1 : (subscribe, CDate)
(CU_id)
table2 : (O_cid)
(O_ref)
table3 : (I_oref)
(I_pid)
table4 : (P_id)
(P_cat)
table5 : (C_id, store)
其次, 如果添加上述索引並沒有像你想的那樣改進,請嘗試將查詢重寫為
SELECT DISTINCT t1.first_name, t1.last_name, t1.email FROM
(SELECT CU_id, t1.first_name, t1.last_name, t1.email
FROM table1
WHERE subscribe = 1 AND
CDate >= $startDate AND
CDate <= $endDate) AS t1
INNER JOIN table2 AS t2
ON t1.CU_id = t2.O_cid
INNER JOIN table3 AS t3
ON t2.O_ref = t3.I_oref
INNER JOIN table4 AS t4
ON t3.I_pid = t4.P_id
INNER JOIN (SELECT C_id FROM table5 WHERE store = 2) AS t5
ON t4.P_cat = t5.C_id
我希望這里第一個子選擇會顯着減少要考慮加入的行數,希望使后續連接做得更少。 同樣在table5上第二個子選擇背后的推理。
無論如何,搞亂它。 我的意思是,最終它只是一個SELECT - 你不能用它真的傷害任何東西。 檢查每個不同排列產生的計划,並試圖找出每個排列的好壞。
分享和享受。
確保您的日期列和您加入的所有列都已編入索引。
在你的日期做一個不等的運算符意味着它檢查每一行,這本質上比等價的慢。
此外,使用DISTINCT可以為優化程序在后台運行的邏輯添加額外的比較。 如果可能的話,消除它。
好吧,首先,創建一個子查詢來將table1抽取到你真正想要加入的所有麻煩的記錄......
SELECT DISTINCT t1.first_name, t1.last_name, t1.email
FROM (
SELECT first_name, last_name, email, CU_id FROM table1 WHERE
table1.subscribe = 1
AND table1.Cdate >= $startDate
AND table1.Cdate <= $endDate
) AS t1
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id
WHERE t5.store = 2
然后開始考慮修改連接的方向性。
另外,如果t5.store只是極少數2,那么請翻轉這個想法:構造t5子查詢,然后將它連接回來,然后返回。
目前,您的查詢返回table2-table5上的所有匹配行,只是為了確定t5.store = 2.如果table2-table5中的任何一行具有比table1高得多的行數,這可能會大大增加處理的行數- 因此,以下查詢可能會表現得更好:
SELECT DISTINCT t1.first_name, t1.last_name, t1.email
FROM table1 AS t1
WHERE t1.subscribe =1
AND t1.Cdate >= $startDate
AND t1.Cdate <= $endDate
AND EXISTS
(SELECT NULL FROM table2 AS t2
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id AND t5.store =2
WHERE t1.CU_id = t2.O_cid);
嘗試在您加入的字段上添加索引。 它可能會也可能不會改善性能。
此外,它還取決於您使用的引擎。 如果您使用的是InnoDB,請檢查您的配置參數。 我遇到了類似的問題,因為innodb的默認配置不會像myisam的默認配置那樣擴展。
正如大家所說,確保你有索引。
您還可以檢查服務器是否已正確設置,以便它可以包含更多內存中的整個數據集。
沒有EXPLAIN,就沒有多少工作了。 還要記住,MySQL將查看您的JOIN,並在執行查詢之前迭代所有可能的解決方案,這可能需要一些時間。 從EXPLAIN獲得最佳JOIN順序后,您可以嘗試在查詢中強制執行此順序,從而從優化程序中刪除此步驟。
聽起來你應該考慮提供子集(分頁)或以其他方式限制結果,除非有一個原因是用戶一次需要所有可能的行。 通常100K行比普通人可以消化的多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.