[英]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.