У меня проблема с проектированием базы данных (SQL/MySQL). Предположим, у нас есть пользователь , пользователь может иметь много друзей и много сообщений и заполнить некоторые данные о себе.Дизайн базы данных - отношения против свойств
Совершенно очевидно, что для friends
нам нужна одна pivot_table для отношения n: n, для posts
нам нужно создать одну дополнительную таблицу с отношением user_id (1: n).
Для этого нам нужны users
, user_friends
и posts
столы. Это очевидно. Вот как следует обращаться с отношениями.
Но теперь давайте предположим, что мы хотим, чтобы для пользователей, чтобы иметь следующие данные:
name - text
description - text
marital status - select only one from list
favourite colour - select only one from list
hobby - select up to 3 from list
Для текстовых полей (название, описание) это действительно очевидно, мы просто создаем VARCHAR/текстовые столбцы в users
таблицы и это все.
Общий вопрос:: как обрабатывать другие поля (выбираемые из списков)? Должен ли я создавать отношения для них или, возможно, следует создавать с ними стандартные столбцы данных?
На мой взгляд, нет смысла создавать таблицы отношений для этого, потому что, используя списки (выберите), мы ограничиваем пользователя, когда он может фактически вставить в базу данных. В теории мы могли бы позволить пользователю вручную вводить в качестве любимого цвета свой цвет (например, red
, и если он что-то неправильно набирает, например, reds
, мы бы сравнили его список разрешенных colours
). То же самое можно сказать и о гендерных вопросах. По моему мнению, нет смысла создавать дополнительную таблицу, когда мы держим только женщину и человека и создаем для нее отношение.
Первый DB дизайн:
Я мог бы, например, создать следующие столбцы для свойств:
marital_status - int
fav_colour - int
hobby_1 - int
hobby_2 - int
hobby_3 - int
И есть еще один стол (или даже простой массив в PHP или другом языке), где я храню, что значение 1 для fav_colour, например, красное, значение 2 для хобби - это музыка и т. д. (неважно, как я храню эти значения здесь - я мог бы также использовать для этого тип enum
).
Для меня преимущества такого отношения не создают много отношений, которые на самом деле скорее являются свойствами, а не отношениями (как я уже упоминал выше), поэтому меньше работы + проще получать информацию о пользователе - вам не нужно использовать какие-либо объединения что было бы важно, если у вас есть для пользователя, например, 20 или 100 таких свойств, и я могу легко искать в пользовательской таблице. Недостатки также совершенно очевидны - данные не нормализованы, для любого множественного выбора (например, для хобби) мне нужно создать 3 столбца, и если в будущем я решите, что пользователь может выбрать не 1 цвет, а 2 или 3, мне нужно будет добавить 2 дополнительных столбца.
Альтернативная конструкция DB:
создать дополнительные таблицы: colours
, hobbies
, marital_statuses
и создать 3 Повороты таблицы: user_colours
, user_hobbies
, user_marital_statuses
. Недостатки: многие присоединяются. Преимущества - если бы я создал 3 дополнительные сводные таблицы, я бы мог легко разрешить пользователю выбирать до 10 цветов, и мне вообще не нужна база редизайна. Но также возникают и недостатки - сложный поиск, большая работа, много объединений.
Детальный вопрос
Так, чтобы подвести итог - какое решение было бы лучше, если предположить:
- я бы, вероятно, не изменить максимальное количество одного свойства (если я решил позволить максимум 3 хобби, это вероятно, никогда не изменится)
- Списки выбора для многих полей будут относительными (для большинства из них менее 10)
- Мне нужно много искать в такой базе данных. Кто-то, например, хочет найти пользователя, у которого fav_colour установлен на красный, и у него есть музыка для хобби.
Если есть какие-либо другие решения или преимущества/недостатки, которые вы видите, я ценю поделиться со мной.
Вот еще один вариант. Создайте таблицу атрибутов с атрибутомName, attributeType, attributeValue, userId. Это позволит вам добавить столько атрибутов пользователю, сколько захотите. Избегайте необходимости вносить изменения схемы в любое время, когда вы думаете о новом бит информации, который вы хотите. – paqogomez
@paqogomez: это анти-паттерн, называемый «сущностью-атрибутом-значением», но, вероятно, решение, которое усугубляет здесь меньше. Другой вариант - хранить «динамические атрибуты» как JSON или XML-документ. Но это очень сложно обрабатывать их в SQL. Третьим вариантом может быть обновление до Postgres и использование функций NoSQL Postgres, таких как тип данных «ключ/значение» «hstore» или встроенная поддержка JSON. –
@a_horse_with_no_name. На самом деле у меня был комментарий, который предложил параметр NoSQL, но удалил его , Я подумал, что это не направление, на которое OP хочет пойти. Это именно тот тип данных, который был создан для NoSQL. – paqogomez