Какой вариант логики запросов правилен?

На странице выводится 10 последних записей из БД. Для каждой из этих записей необходимо отобразить количество комментариев из таблицы `comments`.

1 вариант. При выборке записей для каждой считать комментарии. Получается 1 запрос на выборку + 10 для подсчёта = 11 запросов.
2 вариант. При добавлении комментария увеличивать на 1 поле `count_comments` в таблице с записями. Получается только 1 запрос на выборку.

Какой из этих вариантов более предпочтительнее. Или может быть есть третий?
  • Вопрос задан
  • 2705 просмотров
Пригласить эксперта
Ответы на вопрос 13
Lerg
@Lerg
Defold, Corona, Lua, GameDev
LEFT JOIN и GROUP BY.
Что-то вроде
SELECT
   r.id,
   r.record,
   COUNT(c.id) CountOfComments
FROM records r LEFT JOIN
    comments c ON r.id = c.record_id
GROUP BY r.id
Ответ написан
patashnik
@patashnik
Ещё как вариант:
1-й запрос на выборку комментариев;
2-й запрос вида:
SELECT COUNT(c.id) CountOfComments
FROM comments
WHERE c.record_id IN (... IDS ...)
GROUP BY c.record_id
В IN просто перечисляете ID записей, полученных из 1-го запроса.

Вообще, думаю, что при интенсивных запросах на выборку всех записей вполне подойдет 2-й вариант.
Ответ написан
Powerhead
@Powerhead
По-моему, второй вариант предпочтительней. Он полностью избавит от головной боли в будущем, когда количество данных может увеличиться. Эффективней тратить вычислительные ресурсы в моменты, возникающие реже — в данном случае, добавление/удаление комментариев происходит значительно реже, чем их просмотр.
Реализовать эту логику можно с помощью mysql триггеров, которые будут автоматически обновлять число комментариев при каждом добавлении/удалении

CREATE TRIGGER `comment_add` AFTER INSERT ON `post_comments`
FOR EACH ROW BEGIN
SET @post_id = NEW.post_id;
SET @comments_num = (SELECT COUNT(id) FROM post_comments WHERE post_id = @post_id);
UPDATE `post` SET `comments_num` = @comments_num WHERE `id` = @post_id;
END;


Полный дамп тут
Ответ написан
Wott
@Wott
правильно, с точки зрения нормализации вариант №1, когда нет дублирующей и зависимой информации. Если это не критичное для производительности место, то лучше не создавать лишних сущностей.

Но если запрос такого рода часто используется или выполняется медленно, то стоит ввести дополнительное поле. Имхо лучше делать триггер на изменения в таблице с комментариями и в нем апдейтить поле в таблице с постами, сделать для него дефолт в 0 и вообще забыть о его модификации в приложении.
Ответ написан
Комментировать
Sild
@Sild
Сами записи в другой таблице хранятся? И по каким полям реализуется связь между таблицами?
Ответ написан
@Shecspi Автор вопроса
Спасибо. Буду тестировать различные варианты.
Ответ написан
Комментировать
@Shecspi Автор вопроса
Спасибо. Буду тестировать различные варианты.
Ответ написан
Комментировать
Anonym
@Anonym
Программирую немного )
Палка о двух концах. Очевидные и наиболее адекватные варианты:
1. Выбрать посты, выбрать количество комментариев к ним. Итого 2 SELECT запроса на отображение.
2. Использовать LEFT JOIN и GROUP BY. Итого один, но медленный запрос на отображение.
3. Добавить столбец comments_count в таблицу постов. На отображение будет один быстрый запрос, но на вставку нового комментария добавится один UPDATE (или триггер), плюс нужно будет внимательно следить за этим значением (уменьшать при удалении комментария и т.п.).

Если нагрузка не очень большая, я бы выбрал первый вариант как самый простой в реализации и поддержке. При увеличении нагрузки перешел бы на третий.
Ответ написан
Комментировать
@egorinsk
Только второй вариант. Не слушайте теоретиков. MySQL все эти джойны и аггрегацию никак не соптимизирует.
Ответ написан
@egorinsk
Только второй вариант. Не слушайте теоретиков. MySQL все эти джойны и аггрегацию никак не соптимизирует.
Ответ написан
Комментировать
eaa
@eaa
Поделюсь своим опытом… в старые добрые времена, когда я был еще мелким, мне надо было считать количество комментариев к новостям. Джойны я не любил и применил первый вариант. Потом статистика увеличилась, добавились поля, алгоритмы усложнились. В результате на одну статью стало выполняться по 10-15 селектов. Потом оказалось, что надо показывать не 10 статей, а 50 — итого порядка 500 запросов на одну html-страничку. И не мне это уже понадобилось, а главному программисту, а он недолго думая решил просто вызвать мой метод, не заглядывая, как он реализован. Ну вы можете себе представить его реакцию, когда он посмотрел, как быстро sql пишет запросы в лог-файл :)

Выводы делайте сами.
Ответ написан
Комментировать
@larikov
Однозначно второй, и без различных триггеров в базе, иначе новый разработчик может долго голову чесать думая — почему в коде нет места, где изменяется счетчик комментариев.
Ответ написан
igrishaev
@igrishaev
Однозначно второй способ.
Если у вас используется ORM, то в классе модели комментария в методе сохранения в базу добавьте инкремент счетчика, а в методе удаления — уменьшение.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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