簡體   English   中英

MySQL 之前工作正常的語句突然開始變得非常慢。 它包括很多左連接

[英]MySQL statement that was working fine previously all of a sudden started being very slow. It includes alot of LEFT JOINs

MySQL 關於我幾年前創建的學校系統的聲明運行良好,但現在需要將近 30 秒才能提取在我看來是一個簡單的聲明,但無法弄清楚如何改進它。 我想知道是否有人可以幫助我重新編寫此語句以獲得更快的響應。 聲明是:

SELECT es.*,c.mainsubarea AS subject, b.name,b.email,GROUP_CONCAT(doc.document_file SEPARATOR "|") document_file 
    FROM usersubinfo es 
        LEFT JOIN userinfo b ON (es.uid=b.uid) 
        LEFT JOIN lkptsubjectarea c ON (es.mainsubjectarea=c.id) 
        LEFT JOIN lkptdeliverytime d ON (es.deliverytime = d.id) 
        LEFT JOIN documents doc ON (es.id = doc.order_id) 
    WHERE es.id AND es.is_active='Yes' 
    GROUP BY es.id 
    ORDER BY es.joindate 
    DESC LIMIT 0,25 

請參閱 phpMyAdmin 上的解釋語句的屏幕截圖

首先,考慮編寫一個有效的 ANSI SQL 聚合查詢,更改您的GROUP BYSELECT子句。 目前,您的查詢僅包括GROUP BY中的一列,但usersubinfo表中的所有列都包含SELECT es.*以及其他非聚合列。 您甚至可以按不在GROUP BY中的列排序。

此類查詢針對 SQL 標准運行,並且在大多數 RDBMS 中將失敗,但在 MySQL 中允許,因為它的ONLY_FULL_GROUP_BY模式已關閉,這會危險地允許:

服務器可以從每個組中自由選擇任何值,因此除非它們相同,否則選擇的值是不確定的,這可能不是您想要的

由於您有一個聚合 function, GROUP_CONCAT ,所有其他非聚合列應放在GROUP BY子句中。 如果您需要在SELECT中添加列,請將其也添加到GROUP BY中。 此外,您可能有一個多余的LEFT JOINSELECT的其他JOIN或列沒有任何用途。

SELECT es.id, 
       es.joindate,
       sa.mainsubarea AS subject,
       i.name,
       i.email,
       GROUP_CONCAT(doc.document_file SEPARATOR "|") document_file 
    FROM usersubinfo es 
        LEFT JOIN userinfo i ON (es.uid = i.uid) 
        LEFT JOIN lkptsubjectarea sa ON (es.mainsubjectarea = sa.id) 
        -- LEFT JOIN lkptdeliverytime dlv ON (es.deliverytime = dlv.id)  -- POSSIBLY REDUNDANT
        LEFT JOIN documents doc ON (es.id = doc.order_id) 
    WHERE es.id IS NOT NULL 
      AND es.is_active = 'Yes' 
    GROUP BY es.id,
             es.joindate,
             sa.mainsubarea,
             i.name,
             i.email,
    ORDER BY es.joindate DESC
    LIMIT 0 
    OFFSET 25 

此外,通過避免SELECT *您可以避免引入不需要的甚至更新的列,允許索引在大型表掃描中有效運行,並避免通過網絡發送大量內容。 請參閱為什么 SELECT * 被認為是有害的?

添加索引:這些可能會有所幫助:

b:  INDEX(uid,  name, email)
doc:  INDEX(order_id,  document_file)

刪除 LEFT:是否有LEFT JOIN而不是JOIN的原因? 我想不是。 看看你在沒有LEFTs的情況下是否得到相同的結果。

刪除虛假測試:為什么WHERE es.id 如果idesPRIMARY KEY ,則該測試將始終為真。

改進 GROUP+ORDER:改變

    GROUP BY  es.id
    ORDER BY  es.joindate DESC
    LIMIT  0,25 

-->

    GROUP BY  es.joindate,      es.id
    ORDER BY  es.joindate DESC, es.id DESC
    LIMIT  0,25 

這避免了兩次數據傳遞——一次用於 GROUPing,另一次用於 ORDERing。 同時,我認為我的分組和排序“一樣好”。

由內而外:這帶來了另一個問題,我稱之為“explode-implode”。 這就是你加入很多行的地方,只是為了擺脫其中的大部分。 所以...

首先以盡可能少的努力找到所需的 25 個 ID:

SELECT  id
    FROM usersubinfo
    WHERE is_active = 'Yes'
    GROUP BY  joindate,      id
    ORDER BY  joindate DESC, id DESC
    LIMIT  0,25 

並將其作為“派生”表包含在 rest 中:

SELECT  es.*, c.mainsubarea AS subject,
        b.name, b.email,
        GROUP_CONCAT(doc.document_file SEPARATOR "|") document_file
    FROM ( put the above Select here 
         )  AS ids
    JOIN  usersubinfo AS es  USING(id)
    JOIN  userinfo b  ON (es.uid=b.uid)
    JOIN  lkptsubjectarea c  ON (es.mainsubjectarea=c.id)
    JOIN  lkptdeliverytime d  ON (es.deliverytime = d.id)
    JOIN  documents doc  ON (es.id = doc.order_id)
    ORDER BY  joindate DESC, id DESC;  -- yes, repeat this

這可能會更快,因為除了usersubinfo之外的表只會被觸及 25 次。

(我認為這將避免 Parfait 所指的“only_full_group_by”問題。)

暫無
暫無

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

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