2014-01-22 169 views
1

我有以下查询连接5个InnoDB相关表以获得10行所需的结果集,我尽我所能通过添加索引和以多种不同方式重新编写查询来解决该问题,但我结束了意想不到的结果或非常缓慢的查询。提高MySQL查询性能

下面是该查询

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

目前有超过13000行中的文章表和快速增长的预期。

问题是,这个查询可能需要大量的时间来执行,大约需要3-4秒。我怀疑INNER JION引发了大部分问题,但我想我会问在这里是否有人有任何改进此查询性能的想法。

+0

其中rc.category_id = 1那么你从相关的类别文件开始,因为你已经把它缩小到了一个。希望这是有道理的。从related_category中选择blah rc在rc.id = x.id中加入x其中rc.category_id = 1 – danny117

回答

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 
0

好一个快速的解决办法是摆脱这种

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 
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 

现在,即使在相关条件上面的查询,这样做基于网络的活动(它出现),并从整个子做计数可以是一个巨大的性能损失。你会更好地对数据进行标准化处理。在文章表中,为CommentCount添加一列。然后,当添加任何新的评论,有一个触发插入到基本上没有一个

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

则评论后,你从来没有回去()每一次做的计数。那将是你最好的运营举措。您必须在创建触发器之前默认所有计数,但这将是计数的一次性相关更新。您只需回到相关的文章分类表,以符合您感兴趣的分类标准。