2012-02-04 72 views
2

試圖優化這個查詢,用corollat​​ed子查詢優化corollat​​ed子查詢

SELECT g.*, g.instaLikes + ( SELECT COUNT(*) FROM gallery_likes AS l WHERE l.gallery_id = g.id) AS likes 
FROM gallery AS g 
WHERE ( STATUS = 'approved') 
ORDER BY g.moderated_at DESC , g.id ASC 

的SELECT無子查詢是非常快的,當我嘗試LEFT更慢加入它。

SELECT g.*, (g.instaLikes + COUNT(l.id)) AS likes 
FROM gallery AS g 
LEFT JOIN gallery_likes AS l ON (g.id = l.gallery_id) 
WHERE (STATUS = 'approved) 
GROUP BY g.id 
ORDER BY g.moderated_at DESC , g.id ASC 

,這似乎是最快的是分別做了查詢,然後在PHP循環字段添加在一起,因爲我可以運行一次子查詢,而不是在畫廊n次的選項。

目前在gallery中有2000行,在gallery_likes中有15000行。我認爲我不需要優化,因爲這些數字看起來很低,但第一個查詢需要20-30秒,而LEFT JOIN需要100多秒!

回答

1

在PHP中執行單獨的查詢和加入數據並不是一個壞主意。但是如果你想在SQL中做基本相同的事情,你可以。您可以像處理表一樣處理查詢(即連接它),它們被稱爲派生表。這通常是優化這些類型查詢的更快更簡單的方法。

SELECT g.*, g.instaLikes + l.c 
FROM gallery AS g 
LEFT JOIN (
    SELECT gallery_id, COUNT(*) c FROM gallery_likes GROUP BY gallery_id 
) AS l ON g.id=l.gallery_id 
WHERE ( STATUS = 'approved') 
ORDER BY g.moderated_at DESC , g.id ASC 

這就是將來自gallery_likes的所有記錄分組,這可能是非常低效的。所以你應該添加某種過濾器。如果子選擇(派生表)加入圖庫並使用與外部查詢相同的過濾器,則爲事件。這幾乎和你的第二個查詢類似,但它在加入之前將數據分組。而不是加入,然後分組。

當您需要連接摘要數據(即group by)時,通常這是一個很好的解決方案,但有時可能效率不高。你通常可以通過EXPLAIN告訴。

+0

謝謝 - 我已經遠離做一個子查詢,因爲我想它必須運行主查詢的每一行。這是一個很好的解決方法 - 查詢回到.04秒。 – dmorrow 2012-02-04 20:37:55