Любые идеи о том, как я могу оптимизировать этот запрос? - PullRequest
0 голосов
/ 25 ноября 2011

Этот запрос немного медленный, и я хотел бы его оптимизировать, есть идеи?

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 ]

1 голос
/ 25 ноября 2011
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_read с article, потому что вас интересуют статьи, поэтому вам все равно, есть ли статьи без отношения article_user_read - это можетбыть оптимизирован до JOIN.

Вы также хотите, чтобы статьи имели комментарий после того, как пользователь прочитал статью, поэтому должна существовать связь между article, article_comment и comment - этоможно оптимизировать до JOIN s.

Основное изменение заключается в том, что вам не нужен коррелированный подзапрос (ссылающийся на комментарий c в подзапросе), поэтому JOINот article_user_read до article можно отправить в основной запрос.

0 голосов
/ 25 ноября 2011

Поскольку вас интересуют только отдельные идентификаторы, я бы сделал предварительный запрос только из таблицы article_user_read, так как это является основой вашего WHERE EXISTS, затем связался со статьями и извлекал любые другие столбцы, которые вы хотите ... Кроме того, вы выполняли ЛЕВЫЕ СОЕДИНЕНИЯ, но, в конечном счете, требовали найти, основываясь на соответствующем условии WHERE «c.published_date», что означает, что все записи требуются вплоть до таблицы комментариев. Так что LEFT JOIN не применимо ... единственное, что я бы сделал, это добавлю индекс в таблицу article_user_read ОБА ИД пользователя И ИТОГО флаг Followed.

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 голосов
/ 25 ноября 2011

Учитывая, что вас интересуют только идентификаторы статей в этом запросе, его можно значительно упростить до:

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 голосов
/ 25 ноября 2011

Дикая догадка: замена "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
...