2013-07-26 125 views
0

我需要幫助優化下面的查詢。我有30 + K記錄表pt_votes,其中包含照片的每個投票(-1或1),我想選擇所有的照片和他們的投票總和,所以我有如下查詢,但它需要大約9秒執行。我如何優化它?優化嵌套查詢

SELECT *, ifnull((SELECT SUM(vote) FROM pt_votes vo WHERE vo.pID = ph.pID),0) points, 
         (SELECT CONCAT(name, " ", surname) FROM pt_users us WHERE us.uID = ph.uID) name_surname 
        FROM pt_photos ph 
        WHERE 1 
+0

你可以用特定字段替換*嗎?當您在查詢上執行'EXPLAIN'時會發生什麼?有沒有可以創建/優化的任何鍵? – DevlshOne

+0

你可以添加表結構,它可以是有用的 – CaveCoder

+0

ifnull((SELECT SUM(vote)FROM pt_votes vo WHERE vo.pID = ph.pID),0) 我懷疑這可以被左連接替換,會加速thigs – CaveCoder

回答

0

這裏最大的效率殺手是相關子查詢:

(SELECT CONCAT(name, " ", surname) 
    FROM pt_users us 
    WHERE us.uID = ph.uID) name_surname 

...和:

ifnull((SELECT SUM(vote) 
    FROM pt_votes vo 
    WHERE vo.pID = ph.pID),0) points, 

每個將每一行,使得它過去WHERE條款運行一次。

要消除相關的子查詢,您需要加入pt_votespt_users表。另外,因爲你總結的票數,你需要GROUP BY,這意味着你需要真的擺脫SELECT *正如已經在評論中所建議的。

查詢將如下所示。當你確定哪些pt_photos列,你需要確保將它們添加到列表GROUP BY

SELECT 
    pt_photos.pID, 
    pt_photos.uID, 
    pt_photos.this, 
    pt_photos.that, 
    CONCAT(pt_users.name, ' ', pt_users.surname) AS name_surname, 
    IFNULL(SUM(pt_votes.vote), 0) AS points 
FROM pt_photos 
JOIN pt_users ON pt_photos.uID = pt_users.uID 
LEFT JOIN pt_votes ON pt_photos.pID = pt_votes.pID 
WHERE 1 
GROUP BY 
    pt_photos.pID, 
    pt_photos.uID, 
    pt_photos.this, 
    pt_photos.that 

如果您的查詢真的WHERE 1條款,你可以將其刪除。

0

它不以任何方式進行測試,但嘗試,看看這有助於

SELECT *, SUM(ifnull(vo.vote,0)) points, CONCAT(us.name, " ", us.surname) name_surname 
FROM pt_photos ph 
LEFT JOIN pt_votes vo ON vo.pID = ph.pID 
JOIN pt_users us ON us.uID = ph.uID 
0

使用連接,不相關子查詢。

SELECT ph.*, 
     IFNULL(SUM(vo.vote), 0) points, 
     CONCAT(us.name, " ", us.surname) name_surname 
FROM photos ph 
LEFT JOIN pt_votes vo ON ph.pId = vo.pID 
INNER JOIN pt_users us ON us.uID = ph.uID 
GROUP BY ph.uID 

據我所知,不需要WHERE 1子句來選擇所有行。只要省略WHERE條款。

0

由於執行子查詢的次數,相關的子查詢使大型集合上的亮度調光查詢成爲可能。

這裏應該有更好的表現的替代:

SELECT ph.* 
    , IFNULL(vs.points,0) AS points 
    , CONCAT(us.name," ",us.surname) AS name_surname 
    FROM pt_photos ph 
    LEFT 
    JOIN (SELECT vo.pID 
       , SUM(vo.vote) AS points 
      FROM pt_votes vo 
      GROUP BY vo.pID 
     ) vs 
    ON vs.pID = ph.pID 
    LEFT 
    JOIN pt_users us 
    ON us.uID = ph.uID 
WHERE 1 

上pt_votes合適的索引(理想的是覆蓋索引)將提高GROUP BY的性能......在pt_votes (pID, vote)

我打算假設uID是pt_users的主要關鍵。

0

我會嘗試重寫第三個選擇作爲內部聯接,並可能將concat函數移動到輸出結果時。這是一個T-SQL的解決方案,但它應該是足夠相似:

select ph.*, 
concat(pu.name, " ", pu.surname) as name_surname, 
isnull((select sum(vote) from pt_votes vo where vo.pid = ph.pid),0) as points 
from pt_photos ph 
inner join pt_users pu on ph.uid = pu.uid 

你也可以做一個左連接到pt_votes表的總和,但你不得不「按組」一起玩條款以使其全部工作,這對於處理時間來說可能是值得的。