кто-нибудь знает более эффективный способ выполнения этого запроса?
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
Таблица visit_day имеет одну запись в день, за пользователя, за сообщение. С ростом таблицы этот запрос очень медленный.
Я не могу добавить столбец с общим количеством посещений, потому что мне нужно перечислять сообщения больше посещений в день или неделю и т.д.
Кто-нибудь знает это решение?
Спасибо
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
С 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
. Это значительно ускорит оба варианта.