关于如何优化此查询的任何想法?

时间:2011-11-25 11:01:18

标签: mysql sql performance optimization query-optimization

这个查询有点慢,我想优化它,任何想法?

SELECT DISTINCT a.id
FROM   article a
       LEFT JOIN article_comment ac
         ON a.id = ac.article_id
       LEFT JOIN comment c
         ON ac.id = c.id
WHERE  a.id IN (SELECT a2.id
                  FROM   article_user_read aur
                         LEFT JOIN article a2
                           ON aur.article_id = a2.id
                  WHERE  c.published_date > aur.read_date
                     AND aur.user_id = 36748
                     AND aur.followed = 1)
ORDER  BY c.published_date DESC

这是article_user_read表:

CREATE TABLE `article_user_read` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `article_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `read_date` datetime NOT NULL,
  `followed` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_BBE52A0262922701A76ED395` (`article_id`,`user_id`),
  KEY `IDX_BBE52A0262922701` (`article_id`),
  KEY `IDX_BBE52A02A76ED395` (`user_id`),
  CONSTRAINT `article_user_read_ibfk_3` FOREIGN KEY (`article_id`) REFERENCES `article` (`id`),
  CONSTRAINT `article_user_read_ibfk_4` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20193 DEFAULT CHARSET=latin1;

另一个只是简单的文章&用户表。

4 个答案:

答案 0 :(得分:1)

SELECT DISTINCT a.id
  FROM article AS a

  JOIN article_user_read AS aur
    ON aur.article_id = a.id

  JOIN comment AS c
    ON ac.id = c.id

  JOIN article_comment AS ac
    ON a.id = ac.article_id

 WHERE c.published_date > aur.read_date
   AND aur.user_id = 36748
   AND aur.followed = 1

 ORDER BY c.published_date DESC

LEFT JOIN article_user_readarticle无关,因为您对文章感兴趣,所以您不关心是否有没有article_user_read关系的文章 - - 可以优化为JOIN

您还只想要在用户阅读文章后发表评论的文章,​​因此articlearticle_commentcomment之间的关系必须存在 - 可以优化为{ {1}}秒。

然而,主要的变化是您不需要相关的子查询(在子查询中引用评论JOIN),因此cJOIN之间的article_user_read {1}}可以推送到主查询。

答案 1 :(得分:0)

一个疯狂的猜测:将“IN”替换为“WHERE EXISTS”通常会得到回报:

SELECT DISTINCT a.id
FROM   article a
LEFT JOIN article_comment ac
     ON a.id = ac.article_id
LEFT JOIN comment c
     ON ac.id = c.id
WHERE EXISTS ( 
    SELECT *
    FROM article_user_read aur
    LEFT JOIN article a2
      ON aur.article_id = a2.id
    WHERE  c.published_date > aur.read_date
      AND aur.user_id = 36748
      AND aur.followed = 1
      AND a.id = a2.id
      )
ORDER BY c.published_date DESC

答案 2 :(得分:0)

鉴于您只对此查询中的文章ID感兴趣,因此可以将其简化为:

SELECT a.id
FROM article a
WHERE EXISTS
(SELECT NULL
 FROM article_comment ac
 INNER JOIN comment c ON ac.id = c.id
 INNER JOIN article_user_read aur 
         ON aur.article_id = a.id AND c.published_date > aur.read_date
 WHERE a.id = ac.article_id AND
       aur.user_id = 36748 AND
       aur.followed = 1)

答案 3 :(得分:0)

由于您只关注不同的ID,我只会从article_user_read表中预先查询,因为这是您的WHERE EXISTS的完整基础,然后链接到文章并拉出您想要的任何其他列...此外,您正在进行LEFT JOIN,但最终需要根据“c.published_date”的相应WHERE子句进行查找,这意味着所有条目都需要一直到注释表。所以LEFT JOIN不适用......我唯一要做的就是在用户ID和Followed标志上为article_user_read表添加一个索引。

SELECT distinct 
      aur.article_id
   from 
      article_user_read aur
         join article a
            on aur.article_id = a.id
         join article_comment ac
            on aur.article_id = ac.article_id
            join comment c
               on ac.id = c.id
              and c.published_date > aur.read_date
   where
          aur.user_id = 36748
      and aur.followed = 1