@Avreliya777

Как в mysql ускорить запрос с GROUP BY?

Сначала считаю сколько постов всего есть по тегам из таблицы tags_rel (id, id_tag, id_post) с проиндексированными колонками. ДАНО: юзер запрашивает посты с тегами, id которых равно 1, 2 или 3.
Берём только уникальные значения, конечно же, т.к. на каждый пост по несколько тегов, а значит могут повторяться посты, поэтому с GROUP BY:

SELECT COUNT(*)
FROM
(
	SELECT tags_rel.id
	FROM tags_rel
	LEFT JOIN posts ON tags_rel.id_post = posts.id
	WHERE id_tag IN (1,2,3) AND posts.status = 1
	GROUP BY tags_rel.id_post
) t1

Всё, посчитали, здесь всё отлично, запрос обработан за 0.01сек.
Идём выковыривать теперь сами посты:

SELECT *
FROM
(
	SELECT posts.*
	FROM posts
	LEFT JOIN tags_rel ON tags_rel.id_post = posts.id
	WHERE id_tag IN (1,2,3) AND posts.status = 1
	GROUP BY posts.id
) t1 LIMIT 0,50

И вот здесь всё хорошо ровно до тех пор, пока я не проставлю GROUP BY. Без группировки - сотые доли секунды. С группировкой - уже от 2 секунд и выше, в зависимости от количества найденного.

Как решать такие проблемы?

Думала уже может быстрее вообще все записи без пагинации вытащить, удалить как-то дубли из многомерного массива по колонке id и вытащить из него уже нужные для пагинации номера? Или память всю выжрет?
И сразу вдогонку вопрос может кто сталкиваться, если по FetchAll вытащить всё, как можно наиболее быстро сделать такой перебор многомерного массива на PHP? Можно ли так потягаться в производительности с SQL, или не стоит и пробовать?
  • Вопрос задан
  • 580 просмотров
Решения вопроса 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
SELECT *
  FROM `posts`
  WHERE `id` IN (
    SELECT `id_post`
      FROM `tags_rel`
      WHERE `id_tag` IN (1,2,3)
    ) AND `status` = 1
  LIMIT 0, 50
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Собственно ответ уже был дан выше и отличный по качеству. Хотел лишь уточнить одну "глобальную" мысль. Довольно часто единственным реальным способом ускорить запрос с group by явлется поиск варианта запроса где удастся обойти group by. Потому что группировка по своей сути подразумевает что: вначале мы создаем временное хранилище, туда отгружаем подходящие строки, а после этого по ним пробегаемся ещё процессом группировки (сравнения каждого с каждым). Большие по размеру группировки довольно часто и вовсе вызывают требование создавать для неё временный файл. Ну и сам способ вычисления группировки - небыстрая штука.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы