簡體   English   中英

提高MySQL查詢性能

[英]Improve MySQL Query Performance

我有以下查詢,該查詢連接了5個與InnoDB相關的表,以獲得所需的10行結果集,我盡了最大的努力來解決此問題,方法是添加索引並以許多不同的方式重新編寫查詢,但最終結果還是出乎意料一個非常慢的查詢。

這里是查詢

SELECT 
    a.*,
    c.id as category_id,
    c.title as catname,
    CONCAT(u.fname, ' ', u.lname) as username,
    DATE_FORMAT(a.created, '%W %M %d, %Y - %T') as long_date,
    DATE_FORMAT(a.created, '%d/%m/%Y - %T') as short_date,
    (SELECT 
            COUNT(article_id)
        FROM
            comment
        WHERE 
            article_id = a.id) as totalcomments,
    YEAR(a.created) as year,
    MONTH(a.created) as month,
    DAY(a.created) as day
FROM
    article as a
        INNER JOIN
    article_related_categories rc ON a.id = rc.article_id
        LEFT JOIN
    category as c ON c.id = rc.category_id
        LEFT JOIN
    user as u ON u.id = a.user_id
WHERE
    rc.category_id = 1
        AND a.created <= NOW()
        AND (a.expire = '0000-00-00 00:00:00'
        OR a.expire >= NOW())
        AND a.published IS NOT NULL

ORDER BY a.created DESC
LIMIT 0 , 10

點擊這里查看說明截圖

當前,商品表中有13,000多行,並且有望實現快速增長。

問題是,此查詢可能要花費大量時間才能執行,並且大約需要3-4秒。 我懷疑是INNER JION造成了大多數問題,但我想在這里問是否有人對提高此查詢的性能有任何想法。

嵌套的SELECT可能會減慢速度。 加入comment表和GROUP BY a.id

...
    COUNT(*) as totalcomments,
...    
FROM
    ...
    LEFT JOIN comment AS comm.article_id = a.id
WHERE
    ...
GROUP BY a.id

一個快速的解決方法是擺脫這種情況

    AND a.created <= NOW()

因為將來創建的文章真的沒有意義。 db通常(幾乎總是)少做一件事情就能加快執行速度。

回答的困難在於不知道您真正希望從數據庫中獲得什么。 您需要考慮左連接並在適用的情況下消除它們。 問題在於,如果不刪除具有左聯接和較小結果集的行,就像通過消除行而獲得的結果集那樣,返回結果會更快,因為結果集較小。

為了獲得最佳速度,我將從相關類別表開始,因為我已經將where語句中的結果縮小到1,並且我只查看related_category的一個不同值。

select blah from related_categories rc 
join comment c on r.id = c.id 
join blah b on b.id = c.id
where rc.id = 1

我會在你的桌子上有一個索引

article table index -- ( published, expire, id )
article table index -- ( id ) just the primary key ID for secondary join criteria
article_related_categories table index( article_id, category_id )
comment table (article_id)

然后,進行預查詢,除了獲取ID和商品以及感興趣的相關類別的數量,順序以及對10篇商品的限制外,什么都不做...然后加入類別和用戶表以獲取最終輸出。

SELECT
      a2.*,
      c.id as category_id,
      c.title as catname,
      CONCAT(u.fname, ' ', u.lname) as username,
      DATE_FORMAT(a2.created, '%W %M %d, %Y - %T') as long_date,
      DATE_FORMAT(a2.created, '%d/%m/%Y - %T') as short_date,
      PreQual.TotalComments,
      YEAR(a2.created) as year,
      MONTH(a2.created) as month,
      DAY(a2.created) as day
   from 
      ( select 
              a.id,
              rc.category_id,
              COUNT(c.article_id) as TotalComments
           from 
              article a
                 join article_related_categories rc 
                    ON a.id = rc.article_id
                    AND rc.category_id = 1
                 left join comment c
                    ON a.id = c.article_id
           where
                  a.published IS NOT NULL
              AND (    a.expire >= now()
                    OR a.expire = '0000-00-00 00:00:00' )
           group by
              a.id,
              rc.category_id
           order by
              a.created DESC
           limit
              0, 10 ) PreQual
        JOIN article a2
           ON PreQual.ID = a2.id
           LEFT JOIN user u
              ON a2.user_id = u.id
        LEFT JOIN category as c 
           ON PreQual.Category_ID = c.id

現在,即使使用上面的查詢,進行基於Web的活動(顯示),並在相關條件下對整個子集進行計數也可能對性能產生巨大的影響。 最好從一個方面對數據進行DE-歸一化。 在您的文章表中,為CommentCount添加一列。 然后,當添加任何新評論時,在插入評論后有一個觸發器,基本上可以完成

update Articles
   set CommentCount = CommentCount +1
   where id = the article ID of the new comment ID just inserted.

然后,您不必每次都返回並執行COUNT()。 那將是您最好的操作方法。 在創建觸發器之前,您將必須默認所有計數,但這將是一次相關的計數更新。 您只需要返回相關的文章類別表即可滿足您感興趣的類別標准。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM