どのように私はこのクエリを最適化することができますか?

このクエリは少し遅く、私はそれを、任意のアイデアを最適化したいと思いますか?

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;

The other are just simple article & user table.

0
@Trent、両方のテーブルの id フィールドに、 article_comment comment 実際にコメントのIDは article_comment.id ですか?
追加された 著者 Mark Bannister,
@Trent、それは私たちの質問に答えるものではありません。
追加された 著者 Mark Bannister,
@MarkBannister: ac.comment_id = c.id が私にとって自然であるように思われるので、 ac.id = c.id が間違っていると推測したいと思います。しかし、おそらく私たちが見るものよりもそれ以上のものがあります。
追加された 著者 Andriy M,
「説明する」とは何ですか?あなたはあなたが参加するために使っている列にインデックスを持っていると思いますか?別の結合として "in"句を書き直そうとしましたか?
追加された 著者 Neville Kuyt,
あなたは何らかの形で従属サブクエリ( IN )を取り除かなければならないでしょう。おそらく、テーブルの構造を曖昧にする必要があります(いくつかの article_user_read.read_date 特定の article_id user_id については?)
追加された 著者 Romain,
それでも問題はありますか?
追加された 著者 newtover,
実際には4番目のテーブルがあります。なぜなら、commentはarticle_comment、comment、articleがある単一の継承パターンを使用するからです
追加された 著者 Trent,

4 答え

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

記事に興味があるので、 article LEFT JOIN article_user_read に意味をなさないので、 article_user_read関係のない記事です。これは JOIN に最適化できます。

また、ユーザーが記事を読んだ後にコメントを持つ記事のみが必要なので、 article article_comment comment JOIN に最適化することができます。

しかし、主な変更点は、サブクエリで c という参照サブクエリを必要としないため、 JOIN article_user_read article をメインクエリにプッシュできます。

1
追加された

あなたは別個のIDのみに関心があるので、article_user_readテーブルからpre-queryを実行します。これはWHERE EXISTSの全体的な基礎であり、記事へのリンクと他のどの列でも引き出す​​ためです。さらに、LEFTしかし最終的には、 "c.published_date"のそれぞれのWHERE句に基づいた検索が必要です。これは、すべてのエントリがコメントテーブルまでずっと必要であることを意味します。 LEFT JOINは適用されません。私がやる唯一のもう一つのことは、ユーザIDとフォロードフラグの両方に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
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)
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
0
追加された