Задать вопрос
@GrigoryMorozov

Получение статьи и комментариев к ней: одним запросом или двумя?

Есть таблицы posts и comments. Задача — получить текст поста и комментариев к нему по идентификатору поста. Очевидное решение — использовать LEFT JOIN примерно таким образом:

SELECT p.`content` AS postContent,
       c.`content` AS commentContent
FROM   `posts` AS p
JOIN   `comments` AS c
ON     p.`id` = c.`post`
WHERE  p.`id` = 1


Кажется, что это во всех смыслах хорошее решение — мы используем всего один запрос к базе данных и получаем всю нужную нам информацию. Тем не менее, есть ощущение, что это решение не самое лучшее — ведь, если к посту будет написано большое количество комментариев, текст поста (очевидно, одинаковый для каждого комментария) будет многократно продублирован, а ответ базы данных будет сильно избыточным:

postContent   | commentContent
------------------------------
Текст поста 1 | Комментарий 1
Текст поста 1 | Комментарий 2
Текст поста 1 | Комментарий 3
Текст поста 1 | ...


Собственно, вопрос такой: является ли использование такого запроса оптимальным или, наоборот, неоптимальным решением с точки зрения нагрузки на базу данных, потребления памяти и подобных моментов? Или лучше написать два отдельных запроса для получения текста поста и текста комментариев к нему?

Вопрос кажется очень банальным, но, к сожалению, сходу найти ответ на него не получилось. Заранее спасибо за помощь.
  • Вопрос задан
  • 164 просмотра
Подписаться 3 Простой Комментировать
Решения вопроса 2
@Akina
Сетевой и системный админ, SQL-программист.
Для меня показанный результат как-то неочевидно пригоден к использованию. Куда как симпатичнее смотрится
SELECT 'original post' AS type, content
FROM   posts
WHERE  id = 1

UNION ALL

SELECT 'comment', content
FROM   comments
WHERE  post = 1

ORDER BY type = 'comment'

И один запрос, и никакого дублирования.
Ответ написан
Комментировать
@alexalexes
Вопрос лежит в плоскости оптимизации.
Если вам приемлемо по количеству обращений и времени делать несколько отдельных запросов, чтобы сформировать объект поста на бэкенде перед СУБД, то делайте. Если нужно уменьшить количество запросов, но пожертвовать объемом пересылаемых данных между бэком и СУБД, то какие-то атрибуты поста, которые идут списком/массивом можно получать одним запросом.
Обычно, дилемма состоит в том, как получать необъемные скалярные свойства поста - id, дата публикации, автор и т.д. и не сильно глубоких списков, скажем, изображения галереи поста, которые редко превышает пару десятков штук. Вот это можно спокойно джойнить, и не бояться дублирования свойств поста в выборке.
Если вы работаете с длинным текстом поста, и безразмерными списками, то тут нужны отдельные запросы. Скорее всего в комментариях у вас будет порционная подгрузка по страницам, или по кустам дерева комментариев, если оно многоуровневое.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@rPman
Как это ни странно, но несколько запросов вместо одного большого, хотя и отработают в результате дольше, но повышают эффективность утилизации ресурсов и увеличивают способность базы данных к масштабированию, в т.ч. за счет нескольких серверов. Т.е. при одних и тех же ресурсах (процессор/память/диск), если сравнивать две такие разные реализации, в общем сумеют обработать больше запросов (итоговых страниц) та где много отдельных запросов.

Плюс, отделяя комментарии от основного поста, будет проще расширять функционал и наполнение атрибутами., ведь это совершенно разные сущности, даже если сейчас на начальных стадиях развития проекта у них похожие поля. А еще, кто сказал что комментарии нужно загружать вместе с постом? Кто сказал что их нужно загружать сразу все? достаточно знать их количество (в идеале оценку по высоте страницы для их отображения) и подгружать по мере просмотра (вопрос только про поиск на странице, но и его можно перегрузить), такой подход может значительно разгрузить сервер, когда пользователи начнут работать с постами с сотнями и тысячами комментариев, грузить их все всем просто глупо.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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