Хранение сложной структуры в mysql. Как?

Приветствую.
Имеется проект, посвященный кино, написан на php, js, данные храню в mysql.

Сейчас пишется сервис, который позволит просить совета — «а какой бы фильм мне посмотреть?».

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

Ответ происходит следующим образом:
пользователь пишет коммент к своему ответу и советует парочку фильмов

Главный вопрос: как хранить?

Делать 4 таблицы (коммент запроса, похожие фильмы запроса, коммент ответа, фильмы ответа) не очень хочется во нескольким причинам:
слишком много запросов в БД будет на получение списка запросов на просмотр (запрос, фильмы, кто, что советует)
слишком много лишних телодвижений будет и при ответе

Спасибо.

Скриншоты для лучшего восприятия информации:
image
image
  • Вопрос задан
  • 3527 просмотров
Пригласить эксперта
Ответы на вопрос 9
@kliss
Сделай пока как знаешь. Авось сойдет. Ибо джойны — зло, а premature optimization is the root of all evil :)
Ответ написан
denver
@denver
Делать 4 таблицы (коммент запроса, похожие фильмы запроса, коммент ответа, фильмы ответа) не очень хочется во нескольким причинам:
слишком много запросов в БД будет на получение списка запросов на просмотр

Ерунда, тут всё можно получить в один запрос. И не слишком-то медленный.
Вообще, у вас странная формулировка. Правильно хранить так, как удобнее доставать. Но как доставать нужно вам пишете только мельком. Поэтому пока храните в mysql нормализированно, 4 таблицы это правильно. Если (точнее когда) надо будет ускорить — денормализируйте, только в ту сторону в которую вам надо, а пока не ясно куда.
Ответ написан
Shedal
@Shedal
Делать 4 таблицы (коммент запроса, похожие фильмы запроса, коммент ответа, фильмы ответа) не очень хочется во нескольким причинам:
слишком много запросов в БД будет на получение списка запросов на просмотр (запрос, фильмы, кто, что советует)
слишком много лишних телодвижений будет и при ответе
Что значит слишком много? По сравнению с чем?

Вообще, 4 таблицы — это будет нормализированный способ хранения ваших данных. Можно и денормализировать, но это ухудшит расширяемость и возможности по манипуляци данными средствами SQL. Иногда денормализация приемлема, просто нужно в полной мере осознавать, какими будут последствия.

Например, можно сделать две таблицы: Comments и CommentMovies. В Comments добавить поле IsQuestion, в котором хранить TRUE, если это вопрос и FALSE, если это ответ. CommentMovies будет хранить фильмы как для вопросов, так и для ответов.
Минусом такого подхода будут проблемы функциональной расширяемости. То есть, если вы захотите добавить в таблицу Comments поле, присущее только вопросам, то у вас будет, по сути, три пути:
1) Рефакторинг структуры: разделение на ваши исходные 4 таблицы. Это трудозатратно;
2) Добавление ещё одной таблицы: QuestionCommentFields. Структура получается корявой;
3) Создание поля, которое будет хранить значения только для одного типа строк. Это уже денормализация.

Можно фильмы хранить в виде строки в основной таблице, перечисленными через запятую. Это денормализация, она упростит структуру, но усложнит и замедлит изменение и поиск данных.

В общем, выделите для себя какие-то приоритеты и путеводные камни. Будет ли структура часто меняться в будущем, важна ли простота поддержки? Важна ли скорость выполнения запросов, важна ли возможность менять данные напрямую SQL'ем? И т.п.
Ответ написан
Vidog
@Vidog
Может быть посмотреть в сторону noSQL, например mongoDB или redis. У монго неплохой map/reduce.
Еще можно попробовать postgreSQL — там очень хорошо со структурами таблиц, есть массивы и свои типы — связи между таблицами достаточно просто сделать на нативном уровне.
Ответ написан
@ComodoHacker
Запрос и ответ можно хранить в одной таблице. Списки фильмов, из них — тоже. Получаем две таблицы вместо четырех.
Годится?
Ответ написан
@Neir0
NOSql решения не рассматриваются?
Ответ написан
Сначала напишите на PHP в каком видите вы хотите работать с данными (иерархию объектов, вложенность массивов и т. п.), прикиньте как будете расширять «поля» при необходимости, чтобы не ломать весь код), и только потом думайте как это отобразить на БД. Хотя бы потому что одни и те же отношения между сущностями PHP можно реализовать в БД разными способами, например наследование (от абстрактного «коммента» наследуются «вопрос» и «ответ») отображается минимум тремя способами, а создавая их на основе базы можно просто не заметить, что имеет место какое-то удобное и понятное отношение.

Абстрагируясь от схемы БД вы можете инкапсулировать работу с ней в функции/методы типа $answers = get_answers($question_id) или $answers = Answer.getByQuestion($question) и в них привязывать любую схему БД, или вообще не схему и не БД. Поменяете схему — нужно будет поменять только эти реализации, не трогая основную логику, в ней так и будете обращаться к названию фильма как $questions[$question_id]['answers'][0]['films'][0]['name'] или $questions[$question_id].answers[0].films смотря предпочтётё вы хранить сушности в массивах или объектах.
Ответ написан
Комментировать
ainu
@ainu
Всё уже придумано до нас. Есть схемы связей many_to_many, one_to_many, many_to_one. Комбинируя их, можно легко реализовать схему. Большинство систем для работы с БД (имею в виду AcriteRecord и ORM — составляющие) это умеют.
Кстати, 4 запроса, каждый из которых просматривает 1 строку при поиске, лучше, чем один запрос, просматривающий 10000.
Ответ написан
Комментировать
bergsteiger
@bergsteiger
Попробуйте 1 таблицу для комментов с флагом, означающим «запрс/ответ» и одну таблицу для «прикрепляемых» фильмов… как вариант для «подумать».
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы