簡體   English   中英

如何通過多個連接加速MySQL查詢

[英]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.

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