2015-10-27 72 views
0

我的查詢中遇到了一些困難,其中包含多個左連接以及一個group by和order。與多個左連接,按順序排列的mysql優化

文本表和textdetails包含+ - 800K記錄
複製表和copydetails包含+ - 200K記錄
其他表小了很多。

我有每個列的外鍵我執行一個左連接。 我也在每一列上執行where語句的索引。 下面的MySQL查詢仍然運行大約40秒。 退出羣組通過提高一點。 退出訂單改進了很多。

我做了一些研究,但我仍然對如何改進我的查詢或索引感到困惑。

SELECT * FROM `copy` 
LEFT JOIN `domain` ON domain.domain_id = copy.copy_domain_id 
LEFT JOIN `domaincategory` ON copy.copy_domain_id = domaincategory.domaincategory_domain_id AND domaincategory.domaincategory_account_id = copy.copy_account_id 
LEFT JOIN `text` ON text.text_id = copy.copy_text_id LEFT JOIN `textdetails` ON textdetails.textdetails_text_id = text.text_id 
LEFT JOIN `channel` ON channel.channel_domain_id = domain.domain_id AND channel.channel_account_id = copy.copy_account_id 
LEFT JOIN `feed` ON feed.feed_id = text.text_feed_id 
WHERE (feed.feed_account_id = 96) AND (feed.feed_flag_delete IS NULL) AND (text.text_flag_delete IS NULL) AND (copy.copy_flag_delete IS NULL) AND (copy.copy_tracking_date_found IS NOT NULL) AND (channel.channel_active = 1) 
GROUP BY `copy`.`copy_id` 
ORDER BY `copy`.`copy_tracking_date_found` DESC LIMIT 50 

的EXPLAIN選項的結果如下所示,但我無法弄清楚如何閱讀並使用它正確

ID : 1 
Select_type : SIMPLE 
Table : Feed 
Type : Ref 
Possible_Keys: PRIMARY,fk_feed_account_id,feed_flag_delete 
Key: fk_feed_account_id 
Key_len : 4: 
Ref : const 
Rows : 1 
Extra: Using where; Using temporary; Using filesort 


ID : 1 
Select_type : SIMPLE 
Table : text 
Type : Ref 
Possible_Keys: PRIMARY,fk_text_feed_id,text_flag_delete 
Key: text_flag_delete 
Key_len : 2 
Ref : const 
Rows : 2628 
Extra: Using where 


ID : 1 
Select_type : SIMPLE 
Table : textdetails 
Type : Ref 
Possible_Keys: fk_textdetails_text_id 
Key: fk_textdetails_text_id 
Key_len : 5 
Ref : text.text_id 
Rows : 1 
Extra: 


ID : 1 
Select_type : SIMPLE 
Table : copy 
Type : Ref 
Possible_Keys: fk_copy_account_id,fk_copy_domain_id,fk_copy_text_... 
Key: fk_copy_text_id 
Key_len : 4 
Ref : text.text_id 
Rows : 1 
Extra: Using where 


ID : 1 
Select_type : SIMPLE 
Table : domain 
Type : eq_ref 
Possible_Keys: PRIMARY 
Key: PRIMARY 
Key_len : 4 
Ref : copy.copy_domain_id 
Rows : 1 
Extra: Using where 


ID : 1 
Select_type : SIMPLE 
Table : domaincategory 
Type : eq_ref 
Possible_Keys: fk_domaincategory_account_id,fk_domaincategory_dom 
Key: fk_domaincategory_domain_id 
Key_len : 4 
Ref : domain.domain_id 
Rows : 1 
Extra: 


ID : 1 
Select_type : SIMPLE 
Table : channel 
Type : ref 
Possible_Keys: fk_channel_account_id,fk_channel_domain_id,channel... 
Key: fk_channel_domain_id 
Key_len : 4 
Ref : copy.copy_domain_id 
Rows : 2 
Extra: Using where 

也許我應該解釋的關係多一點?
飼料:文本= 1:n的
文本:textdetails = 1:1
文本:複製= 1:n的
副本:域= N:1
信道:域中的N個:1

+0

你需要有MySQL的解釋查詢做:https://dev.mysql.com/doc/refman/5.5/en/execution-plan -information.html – mikeb

+0

爲什麼你不編輯你的問題併發布它們? – mikeb

+0

我剛剛做到了。似乎無法弄清楚如何正確讀取EXPLAIN功能 – quibuz

回答

0

相當幾件事情我會改變,並已更新查詢來反映這一點。另外,對於索引。如果你在每一列都有索引,但是它們是單獨的索引,那WONT一定會幫助你。您需要複合(多字段)索引以更好地匹配您的聯接/如果可能的話,標準和分組。

SELECT 
     * 
    FROM 
     feed f 
     JOIN text t 
      ON feed.feed_id = t.text_feed_id 
      LEFT JOIN textdetails td 
       ON t.text_id = td.textdetails_text_id 
      JOIN COPY c 
       ON t.text_id = c.copy_text_id 
       LEFT JOIN domain d 
        ON c.copy_domain_id = d.domain_id 
       LEFT JOIN domaincategory dc 
        ON c.copy_domain_id = dc.domaincategory_domain_id 
        AND c.copy_account_id = cd.domaincategory_account_id 
       JOIN channel ch 
        ON c.copy_account_id = ch.channel_account_id 
        AND c.copy_domain_id = ch.channel_domain_id 
        AND ch.channel_active = 1 
    WHERE 
      f.feed_account_id = 96 
     AND f.feed_flag_delete IS NULL 
     AND t.text_flag_delete IS NULL 
     AND c.copy_flag_delete IS NULL 
     AND c.copy_tracking_date_found IS NOT NULL 
    GROUP BY 
     c.copy_id 
    ORDER BY 
     c.copy_tracking_date_found DESC 
    LIMIT 
     50 

Transitive Property
由於copy.copy_domain_id是加盟domain.domain_id和channel.channel_domain_id連接到domain.domain_id,我們只要改變copy.copy_domain_id = channel.channel_domain_id,並且不需要分裂加盟到其他相同值的不同表格。

第二...你有左連接,但是當你添加「feed_account_id = 96」時,你會自動將它轉換爲INNER JOIN,因爲這是一個需求,因此也使TEXT別名成爲連接。與Channel_Active = 1的CHANNEL表類似(我有更新查詢以反映這一點)。

現在,由於基於特定帳戶的FEED表進行排位,我已將其移至第一個FROM位置並加入到複製表中。現在

,索引來幫助優化該

table  index 
feed   (feed_account_id, feed_id, feed_flag_delete) 
text   (text_feed_id, text_id, text_flag_delete) 
textdetails (textdetails_text_id) 
copy   (copy_text_id, copy_domain_id, copy_account_id, copy_flag_delete, copy_tracking_date_found, copy_id) 
domain  (domain_id) 
domaincategory (domaincategory_domain_id, domaincategory_account_id) 
channel  (channel_domain_id, channel_account_id, channel_active) 
+0

感謝DRapp的廣泛解釋。 我試圖把它全部弄清楚。 我實現您的解決方案,並嘗試了2個帳戶 - 第一個帳戶擁有1種飼料,40K text_id的連接10K copy_id的 - 第二帳戶有5種飼料,70K text_id的連接150K copy_id的 第一個帳戶查詢了大約1秒。 對於第二個帳戶,查詢仍然花費了40+秒。 – quibuz

+0

@quibuz,多一個選項...添加一個關鍵字... SELECT STRAIGHT_JOIN ... STRAIGHT_JOIN關鍵字告訴引擎按照我列出的方式運行。看看這是如何工作的,還有......在第二個帳戶的結果集中有多少記錄被返回。另一個問題是做SELECT *是瘋狂的,並從所有表中獲取所有字段。你真的應該儘量避免這種情況,並得到你需要的東西,不僅僅是因爲它在那裏。讓我知道STRAIGHT_JOIN是如何爲你和時間/記錄工作的。 – DRapp