MySql Присоединяйтесь медленно с SUM () результатов - PullRequest
0 голосов
/ 25 июня 2018

Кто-нибудь знает более эффективный способ выполнить этот запрос?

SELECT SQL_CALC_FOUND_ROWS p.*, IFNULL(SUM(v.visits),0) AS visits,
FROM posts AS p 

LEFT JOIN visits_day v ON v.post_id=p.post_id 

GROUP BY post_id 
ORDER BY post_id DESC LIMIT 20 OFFSET 0

Таблица посещений содержит одну запись в день на пользователя и на сообщение. С ростом таблицы этот запрос чрезвычайно медленный.

Я не могу добавить столбец с общим количеством посещений, потому что мне нужно перечислить сообщения по большему количеству посещений в день или за неделю и т. Д.

Кто-нибудь знает лучшее решение для этого?

Спасибо

CREATE TABLE `visits_day` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `post_id` int(11) NOT NULL,
 `user_id` int(11) NOT NULL,
 `day` date NOT NULL,
 `visits` int(11) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=52302 DEFAULT CHARSET=utf8

CREATE TABLE `posts` (
 `post_id` int(11) NOT NULL AUTO_INCREMENT,
 `link` varchar(300) NOT NULL,
 `date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `title` varchar(500) NOT NULL,
 `img` varchar(300) NOT NULL,
 PRIMARY KEY (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1027 DEFAULT CHARSET=utf8

1 Ответ

0 голосов
/ 25 июня 2018

С SQL_CALC_FOUND_ROWS запрос должен оценивать все, но не доставлять все строки. Избавление от этого должно быть полезным.

Чтобы фактически коснуться только 20 строк, нам нужно пройти через WHERE, GROUP BY и ORDER BY с одним индексом. В противном случае нам, возможно, придется коснуться всех строк, отсортировать их и затем поставить 20. Очевидный индекс - (post_id); Я подозреваю, что это уже проиндексировано как PRIMARY KEY(post_id)? (Будет полезно, если вы зададите SHOW CREATE TABLE при задании вопросов.)

Другой способ выполнить объединение и получить желаемый результат, равный нулю, заключается в следующем. Обратите внимание, что это устраняет необходимость в GROUP BY.

SELECT p.*,
       IFNULL( ( SELECT SUM(v.visits)
                   FROM visits_day
                   WHERE post_id = p.post_id
               ),
            0) AS visits
    FROM posts AS p 
    ORDER BY post_id DESC
    LIMIT 20 OFFSET 0

Если вы действительно нуждаетесь в подсчете, рассмотрите SELECT COUNT(*) FROM posts.

ON v.post_id=p.post_id в вашем запросе и WHERE post_id = p.post_id просят INDEX(post_id) на visits_day. Это значительно ускорит оба варианта.

...