2013-05-16 27 views
0

我正在構建一個複雜的多表MySQL查詢,即使它工作,我想知道我可以使它更簡單。這是這個複雜的MySQL多表查詢的最佳方法嗎?

它背後的想法是,使用記錄所有網站交互的事件表,選擇10個最受歡迎的博客帖子的ID,標題和Slug,並按大多數命中降序排序。

SELECT content.id, content.title, content.slug, COUNT(events.id) AS hits 
FROM content, events 
WHERE events.created >= DATE_SUB(NOW(), INTERVAL 1 MONTH) 
    AND events.page_url REGEXP '^/posts/[0-9]' 
    AND content.id = events.content_id 
GROUP BY content.id 
ORDER BY hits DESC 
LIMIT 10 

博客文章的URL具有以下格式:

/posts/2013-05-16-hello-world 

正如我所提到它似乎工作,但我敢肯定,我可以做這個乾淨。

感謝,

+2

您應該使用ANSI JOIN語法,但除此之外,它看起來很簡單的給我。 – Barmar

+0

除了不使用'JOIN'外,'REGEXP'對我來說是醜陋的一部分。如果'events'表可以按類型對事件進行分類會更好,所以你只需要尋找'events.type ='post''之類的東西。 (我有點猜測爲什麼你甚至需要首先看一下'page_url',可能有一些'events'是同一件'content'的,不應該被計算在內。) – grossvogel

回答

1

而不是一個正則表達式,你可以使用left功能:

SELECT content.id, content.title, content.slug, COUNT(events.id) AS hits FROM content JOIN events ON content.id = events.content_id 
      WHERE events.created >= DATE_SUB(NOW(), INTERVAL 1 MONTH) 
      AND left(events.page_url, 7) = '/posts/' 
      GROUP BY content.id 
      ORDER BY hits DESC 
      LIMIT 10) 

但是,這只是我的頭頂部,並且沒有fiddle,未經測試。在評論中提出的JOIN建議也很好,並已在我的回答中得到反映。

+2

REGEXP中的'^'意味着它必須開始'/ posts /',所以如果你打算這樣做(不強制執行一個數字),那麼使用'LEFT( events.page_url,7)='/ posts /' –

+0

完全正確,更新爲使用左邊 – hd1

+0

,因爲我們正在改變問題並推斷日期部分並不重要......我認爲''''會更便宜'事件.page_url like'/ posts /%'' – gillyspy

1

條件created和條件page_url都是範圍條件。您可以在SQL查詢中爲每個表的一個範圍條件獲取索引幫助,因此您必須選擇其中一個索引。

我會創造超過兩列(的content_id,創建)的事件表的索引。

ALTER TABLE events ADD KEY (content_id, created); 

我假設,通過創建日期限制是比PAGE_URL限制更多的選擇性,因爲我認爲「/職位/」將絕大多數的事件相匹配。

通過創建日期縮小匹配行後,頁面url條件將必須由SQL層處理,但希望這不會太低效。

有SQL-89之間沒有性能上的差異( 「逗號式」)連接語法和SQL-92 JOIN語法。我不建議您使用SQL-92語法,因爲它更清晰,並支持外部連接,但性能不是一個理由去使用它。 SQL查詢優化器支持兩種連接樣式。

臨時表和文件排序往往是昂貴的性能。這個查詢必然會創建一個臨時表並使用一個filesort,因爲您正在對不同的列使用GROUP BY和ORDER BY。您只能希望臨時表的大小足以滿足您的tmp_table_size限制(或增加該值)。但是,如果content.title或content.slug是BLOB/TEXT列,那麼臨時表將被強制在磁盤上後臺處理。

相關問題