2012-02-24 78 views
3

我有一個數據庫結構與下面的協會服務了新聞報道:提高了許多LEFT一個SQL查詢的性能JOIN的

  • HABTM news_categories
  • HABTM標籤
  • HABTM上傳

我寫了一條SQL查詢將所有這一切拉到一起:

SELECT `news_articles`.*, 
GROUP_CONCAT(DISTINCT tags.title) AS `tags`, 
GROUP_CONCAT(DISTINCT tags.id) AS `tag_ids`, 
GROUP_CONCAT(DISTINCT news_categories.title) AS `news_categories`, 
GROUP_CONCAT(DISTINCT news_categories.id) AS `news_category_ids`, 
GROUP_CONCAT(DISTINCT news_categories.slug) AS `news_category_slugs`, 
`news_articles_uploads`.`caption` AS `upload_caption`, 
`uploads`.`title` AS `upload_title`, 
`uploads`.`basename` AS `upload_basename`, 
`uploads`.`extension` AS `upload_extension`, 
`uploads`.`path` AS `upload_path` 
FROM `news_articles` 
LEFT JOIN `news_articles_tags` ON news_articles_tags.news_article_id = news_articles.id 
LEFT JOIN `tags` ON news_articles_tags.tag_id = tags.id 
LEFT JOIN `news_articles_news_categories` ON news_articles_news_categories.news_article_id = news_articles.id 
LEFT JOIN `news_categories` ON news_articles_news_categories.news_category_id = news_categories.id 
LEFT JOIN `news_articles_uploads` ON (news_articles_uploads.news_article_id = news_articles.id AND news_articles_uploads.order = 0) 
LEFT JOIN `uploads` ON news_articles_uploads.upload_id = uploads.id 
WHERE (news_categories.slug IN ("category-one","category-two","category-three","category-four","category-five")) AND (news_articles.published = 1) 
GROUP BY `news_articles`.`id` 
ORDER BY `news_articles`.`lead_article` DESC, `news_articles`.`created` DESC LIMIT 20; 

問題是,在查詢運行時,速度很慢,而在繁忙時段,CPU使用率變得非常不可收拾!

下面是一個解釋上面的查詢(右鍵單擊在新標籤中打開看原圖):

Explain result for the above query

你可以在這裏找到的模式:http://pastie.org/private/qoe2qo16rbqr5mptb4bug

的服務器運行MySQL 5.1.55,網站使用Zend Framework來執行查詢和PHP 5.2.8。

我已經通過MySQL慢速查詢日誌,並添加了我所知道的最好的缺失索引,但查詢仍顯示爲需要1-3秒才能執行。如果有人有任何想法,我非常感激。提前致謝。

回答

3

由於您的「WHERE」子句最初在您的新聞類別中包含「AND」的 指定的列表,因此強制INNER加入的連接不是LEFT JOIN。 另外,我會嘗試添加「STRAIGHT_JOIN」子句。這通常會強制引擎 以特別聲明的順序執行加入,而不是試圖爲您自己設想 替代方案......尤其是當其他表格更「查找」引用時。

我也會應用喬丹建議的指數。

SELECT STRAIGHT_JOIN 
     NA.*, 
     GROUP_CONCAT(DISTINCT tags.title) AS `tags`, 
     GROUP_CONCAT(DISTINCT tags.id) AS tag_ids, 
     GROUP_CONCAT(DISTINCT NC.title) AS news_categories, 
     GROUP_CONCAT(DISTINCT NC.id) AS news_category_ids, 
     GROUP_CONCAT(DISTINCT NC.slug) AS news_category_slugs, 
     NAUp.`caption` AS upload_caption, 
     Up1.`title` AS upload_title, 
     Up1.`basename` AS upload_basename, 
     Up1.`extension` AS upload_extension, 
     Up1.`path` AS upload_path 
    FROM 
     news_articles NA 
     INNER JOIN news_articles_news_categories NACats 
      ON NA.id = NACats.news_article_id 

      INNER JOIN news_categories NC 
       ON NACats.news_category_id = NC.id 
       AND NC.slug IN ("category-one", 
           "category-two", 
           "category-three", 
           "category-four", 
           "category-five") 


     LEFT JOIN news_articles_tags NATags 
      ON NA.ID = NATags.news_article_id 

      LEFT JOIN tags 
       ON NATags.tag_id = tags.id 

     LEFT JOIN news_articles_uploads NAUp 
      ON NA.ID = NAUp.news_article_id 
       AND NAUp.order = 0 

      LEFT JOIN uploads Up1 
       ON NAUp.upload_id = Up1.id 

    WHERE 
     NA.Published = 1 
    GROUP BY 
     NA.ID 
    ORDER BY 
     NA.lead_article DESC, 
     NA.created DESC 
    LIMIT 20; 
+0

謝謝,我會放棄這個! – BeesonBison 2012-02-24 17:49:04

3

你有一個索引news_articleslead_articlenews_articlescreated,這是一個包含兩列的索引。

create index news_articles_x1 on news_articles (lead_articles, created); 

沒有它,你將不會利用limit子句的順序,它仍然會掃描整個表並進行排序。

另外我會問你是否需要在一次爆炸中的所有這些數據?

+0

+1「你需要的所有數據在一個爆炸」,但你從指數... – Ben 2012-02-24 11:37:08

+0

感謝您的答覆錯過了'news_articles.id',我創建了BYT指數EXPLAIN結果仍然相同。我應該看到有什麼不同嗎? – BeesonBison 2012-02-24 12:15:33

+0

所有的數據在一起去了......我可能會失去標籤,但def。需要類別並上傳連接。 – BeesonBison 2012-02-24 12:16:20