【问题标题】:Any ideas on how could I optimize this query?关于如何优化此查询的任何想法?
【发布时间】:2011-11-25 11:01:18
【问题描述】:

这个查询有点慢,我想优化一下,有什么想法吗?

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;

其他只是简单的文章和用户表。

【问题讨论】:

  • “解释”说什么?我假设您在用于加入的列上有索引?您是否尝试过将“in”子句重写为另一个联接?
  • 您必须以某种方式摆脱依赖子查询 (IN),我们可能需要了解您的表的结构(对于给定的 @ 可以有几个 article_user_read.read_date 987654325@ 和 user_id ?)
  • @Trent,如果article_commentcomment 之间的链接在两个表的id 字段上 - 即。 article_comment.id 实际上是评论的 ID 吗?
  • @MarkBannister:我宁愿认为ac.id = c.id 是不正确的,因为ac.comment_id = c.id 对我来说似乎更有可能和自然。但也许它比我们所看到的更多。
  • 其实还有第四张表,因为comment是单继承模式,这里有article_comment,comment,article

标签: mysql sql performance optimization query-optimization


【解决方案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之间的关系必须存在——可以优化为JOINs。

然而,主要变化是您不需要相关的子查询(在子查询中引用注释c),因此article_user_readarticle 之间的JOIN 可以推送到主要查询。

【讨论】:

    【解决方案2】:

    一个大胆的猜测:将“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
    

    【讨论】:

      【解决方案3】:

      鉴于您只对此查询中的文章 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)
      

      【讨论】:

        【解决方案4】:

        由于您只关心不同的 ID,因此我将仅从 article_user_read 表中进行预查询,因为这是您的 WHERE EXISTS 的全部基础,然后链接到文章并提取您想要的任何其他列...此外,您正在执行 LEFT JOIN,但最终需要根据“c.published_date”的相应 WHERE 子句进行查找,这意味着所有条目都需要一直到 cmets 表。所以 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-01
          • 2023-04-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多