2014-02-17 51 views
1

我有這個SQL查詢抓取5個最新的新聞帖子。我想做到這一點,所以它也抓住了相同查詢中的總喜歡和總新聞評論。但是當我處理大量數據時,我所做的查詢似乎有點慢,所以我試圖查看是否可以找到更好的解決方案。這是如下:如何使用多個表優化SQL查詢

SELECT *, 
`id` as `newscode`, 
(SELECT COUNT(*) FROM `likes` WHERE `type`="newspost" AND `code`=`newscode`) as `total_likes`, 
(SELECT COUNT(*) FROM `news_comments` WHERE `post_id`=`newscode`) as `total_comments` 
FROM `news` ORDER BY `id` DESC LIMIT 5 

這裏是一個SQLFiddle還有:http://sqlfiddle.com/#!2/d3ecbf/1

回答

0

你可以這樣使用重寫加入,MySQL在已知問題的子查詢,尤其是對於大型數據集時:

SELECT n.*, 
     `id` as `newscode`, 
     COALESCE(l.TotalLikes, 0) AS `total_likes`, 
     COALESCE(c.TotalComments, 0) AS `total_comments` 
FROM `news` n 
     LEFT JOIN 
     ( SELECT Code, COUNT(*) AS TotalLikes 
      FROM `likes` 
      WHERE `type` = "newspost" 
      GROUP BY Code 
     ) AS l 
      ON l.`code` = n.`id` 
     LEFT JOIN 
     ( SELECT post_id, COUNT(*) AS TotalComments 
      FROM `news_comments` 
      GROUP BY post_id 
     ) AS c 
      ON c.`post_id` = n.`id` 
ORDER BY n.`id` DESC LIMIT 5; 

的原因是,當您使用如上聯接,MySQL將物化的結果當第一次需要它的子查詢,如在此查詢的開始,MySQL將投入的結果:

SELECT post_id, COUNT(*) AS TotalComments 
FROM `news_comments` 
GROUP BY post_id 

到存儲表和哈希POST_ID更快的查找。然後,對於news中的每一行,只需從該散列表中查找TotalComments,當您使用相關子查詢時,它將爲news中的每一行執行一次查詢,當news較大時將導致大量執行。如果初始結果集很小,您可能看不到性能優勢,並且可能會更糟。在SQL小提琴

最後

例子,你可能想指數news_commentslikes相關領域。對於這個特定的查詢我認爲以下指標將幫助:

CREATE INDEX IX_Likes_Code_Type ON Likes (Code, Type); 
CREATE INDEX IX_newcomments_post_id ON news_comments (post_id); 

雖然你可能需要將第一指數分爲兩個:

CREATE INDEX IX_Likes_Code ON Likes (Code); 
CREATE INDEX IX_Likes_Type ON Likes (Type); 
+0

當運行這個時,我在'on clause'中得到錯誤'未知列'n.newscode'。 – user3205106

+0

你是什麼意思?有單獨的表格。 – user3205106

+0

在獲取'total_likes'的子查詢中,您在WHERE子句中使用了這個:'\'code \'= \'newscode \''。 'newscode'在這裏指的是什麼?我知道他們是獨立的桌子,但大概他們有聯繫?否則,你只是得到喜歡的總數,除非有關係,否則對每一行都是相同的。 – GarethD

0

幫助在列的索引IDPOST_ID類型,代碼首先檢查。

0

我認爲這是T-SQL,因爲這是我最熟悉的。

首先我會檢查索引。如果這看起來不錯,那麼我會檢查陳述。看看你的查詢地圖,看看它是如何填充你的結果。

SQL反向工作,所以它從最後的AND聲明開始並從那裏開始。它將通過代碼對它們進行分組,然後輸入,最後給你一個計數。

現在,無論日期如何,您都可以使用特定代碼獲取所有內容。當你說你想要最新的時候,我假設有一個日期列的地方。

爲了加快速度,請將另一個AND添加到您的WHERE並記錄日期。無論是最近24小時,上週,無論如何。

+1

與T-SQL相關的問題的假設是由於該問題標記爲MySQL。 SQL向後工作的聲明從最後一個AND聲明開始,它不是真的,它從您選擇的表開始,然後處理任何聯接(除非您另有說明,否則它以任何它認爲合適的順序),然​​後處理與你的where子句一樣,再次以優化者認爲最快的順序。 – GarethD

+0

你說得對,我沒有檢查標籤。顯然,SQL始於表聚合'FROM',但是在那之後,數據絕對被解析爲'後':WHERE,GROUP,HAVING,SELECT,ORDER BY。我的建議是在處理表和連接之後改進WHERE子句,這是下一步。 – Phoenix

1

我會建議增加一個total_likestotal_comments領域的news只要添加或刪除了類似和/或註釋,就會增加/減少表格。

您的likesnews_comments表只應用於歷史目的。

每次頁面加載時都不應該進行這種艱苦的計數,因爲這是一個完全浪費的資源。

+0

@ user3205106,我也在那裏,但它應該在INSERT觸發器中進入likes/comments表。這是一個常見問題,特別是對於網絡來說,DENORMALIZE的計數會導致查詢被抓取。 – DRapp

+0

謝謝@DRapp我假設你忘了提及DELETE和INSERT,因爲一般來說用戶通常可以執行Like和Un-Like操作,除非OP將它們鎖定在他們喜歡的東西的決定上。同樣的規則也適用於評論,同時考慮到評論可能會被緩和的事實。因此,我的答案增加/減少部分。 – MonkeyZeus

+0

是正確的,它應該在插入,更新和刪除,但觸發器仍然是總數非規範化的更好考慮。 – DRapp