我有以下查询连接5个InnoDB相关表以获得10行的所需结果集,我尽力通过添加索引并以多种不同方式重新编写查询来解决问题,但我最终要么意外的结果或非常缓慢的查询。
这里是QUERY
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
Click Here to see the explain screenshot
目前文章表中有超过13,000行,预计会有快速增长。
问题是,此查询可能需要大量时间才能执行,大约需要3-4秒。我怀疑INNER JION导致了大部分问题,但我想我会在这里询问是否有人提出改进此查询性能的任何想法。
答案 0 :(得分:0)
嵌套SELECT
可能会减慢速度。加入comment
表和GROUP BY a.id
:
...
COUNT(*) as totalcomments,
...
FROM
...
LEFT JOIN comment AS comm.article_id = a.id
WHERE
...
GROUP BY a.id
答案 1 :(得分:0)
快速修复就是摆脱这个
AND a.created <= NOW()
因为将来创建的文章确实没有意义。数据库通常(几乎总是)做的事情少一点就会导致执行速度加快。
回答的难点是不知道你真正希望从数据库获得什么。您需要考虑左连接并在适用的情况下消除它们。问题是你没有删除左连接的行和较小的结果集,就像你通过消除行返回的那些更简单,因为结果集更小。
为了获得最佳速度,我将从相关类别表开始,因为我已经将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
答案 2 :(得分:0)
我会在你的桌子上有一个索引
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()。这将是您最好的操作行动。在创建触发器之前,您必须默认所有计数,但这将是计数的一次性相关更新。您只需要返回相关的文章类别表,以符合您感兴趣的类别标准。