ненужная нормализация - PullRequest
       41

ненужная нормализация

10 голосов
/ 10 сентября 2010

Мой друг и я строим веб-сайт и имеем серьезные разногласия. Ядром сайта является база комментариев о «людях». В основном люди могут вводить комментарии, и они могут вводить человека, о котором идет комментарий. Затем зрители могут искать в базе данных слова, которые есть в комментарии или части имени человека. Это полностью пользовательский. Например, если кто-то хочет опубликовать комментарий к неверной версии имени человека, он может, и это нормально. Таким образом, может быть несколько написаний разных людей, перечисленных как несколько разных записей (некоторые с отчеством, некоторые с псевдонимом, некоторые неправильно написанные и т. Д.), Но это все в порядке. Нам все равно, если люди комментируют случайных людей или воображаемых людей.

В любом случае, проблема в том, как мы структурируем базу данных. Сейчас это всего лишь одна таблица с идентификатором комментария в качестве первичного ключа, а затем есть поле для «лица», о котором идет комментарий:

идентификатор комментария - комментарий - человек

1 - «он странный» - Джон Смит

2 - "Вонючая девушка" - Дженни

3 - «гей» - Джон Смит

4 - "должен мне 20 долларов" - Дженныыыыыыыыы

Все работает нормально. Используя базу данных, я могу создавать страницы, которые содержат все «комментарии» для конкретного «человека». Однако он одержим тем, что база данных не нормализована. Я прочитал о нормализации и узнал, что он был неправ. Таблица в настоящее время нормализована, потому что идентификатор комментария является уникальным и диктует «комментарий» и «лицо». Теперь он настаивает на том, чтобы у «человека» был свой СОБСТВЕННЫЙ стол, потому что это «вещь». Я не думаю, что это необходимо, потому что, хотя «человек» на самом деле является большим контейнером (один «человек» может иметь много «комментариев» о них), база данных, кажется, работает нормально, а «человек» является атрибутом идентификатор комментария. Я использую различные вызовы PHP для разных вариантов выбора SQL, чтобы волшебно выглядеть более изощренным на выходе и по-разному, как пользователь может искать и видеть результаты, но на самом деле настройка довольно проста. Теперь я позволяю пользователям оценивать комментарии большим и большим пальцами, и я сохраняю «счет» как другое поле в той же таблице.

Я чувствую, что в настоящее время нет необходимости иметь отдельную таблицу только для уникальных записей о людях, потому что у людей нет собственной оценки или каких-либо собственных атрибутов. Только комментарии делают. Мой друг настолько настойчив, что это необходимо для эффективности. Наконец, я сказал: «Хорошо, если вы хотите, чтобы я создал отдельную таблицу, и пусть« person »будет ее собственным полем, тогда каким будет второе поле? Потому что, если таблица имеет только один столбец, это кажется бессмысленным. Я согласен что позже мы можем создать необходимость предоставить «человеку» свой собственный стол, но тогда мы сможем с этим справиться ». Затем он сказал, что строки не могут быть первичными ключами, и что мы будем преобразовывать «лиц» в текущей таблице в числа, а числа будут первичным ключом в новой таблице «человек». Мне это кажется ненужным, и это усложнит чтение текущей таблицы. Он также считает, что создать вторую таблицу позже будет невозможно, и сейчас нам нужно предвидеть, что она может понадобиться нам позже.

Кто прав?

Ответы [ 11 ]

9 голосов
/ 10 сентября 2010

На мой взгляд, ваш друг прав.

Человек должен жить за другим столом, и вы должны попытаться нормализоваться.Не переусердствуйте, хотя.

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

8 голосов
/ 10 сентября 2010

Создание новой таблицы для персоны и использование ключа этой таблицы вместо атрибута персоны не имеет ничего общего с нормализацией.Это может быть хорошей идеей по другим причинам, но это не делает базу данных «более нормализованной», чем если вы этого не сделаете.Так что вы правы: что касается нормализации, создание другой таблицы не требуется.

3 голосов
/ 10 сентября 2010

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

2 голосов
/ 10 сентября 2010

Ты прав.

Person может быть вещь в целом, но не в вашей модели. Если вы хотите, чтобы люди правильно идентифицировали человека, о котором они говорят, понадобится таблица Person. Например, если комментарии касались только лиц, уже зарегистрированных в базе данных.

Но здесь, похоже, у вас есть неструктурированные данные без идентичности; и что ничто / никто не заинтересован в том, чтобы убедиться, что "Дженни" и "Дженни" на самом деле - это одно и то же лицо, не говоря уже о "Дженни Доу" и "моем двоюродном брате" ...

2 голосов
/ 10 сентября 2010

Если вы уже достигли всех своих возможностей и у вас нет планов по расширению возможностей, я думаю, вы оставите все как есть.

Если вы планируете добавить больше, а именно разрешить людям иметь учетные записи или что-то действительно, я думаю, что было бы разумно разделить ваши данные на таблицы Person, Comments. Это не сложно и облегчает расширение вашей функциональности.

1 голос
/ 11 сентября 2010

Если вы никогда не намереваетесь связывать столбец person с пользователем или чем-либо еще, и данные, по-видимому, не нуждаются в проверке согласованности или целостности данных, почему это вообще происходит в реляционной базе данных?Разве это не вариант использования базы данных nosql?Или я что-то упустил?

1 голос
/ 11 сентября 2010

Нормализация - это все о функциональных зависимостях (FD). Вам необходимо идентифицировать все из FD, которые существуют среди атрибутов вашей модели данных, прежде чем она может быть полностью нормализована.

Давайте рассмотрим, что у вас есть:

  • Любой данный экземпляр CommentId функционально определяет Person (FD: CommentId -> Person)
  • Любой данный экземпляр CommentId функционально определяет Comment (FD: CommentId -> Comment)
  • Любой данный экземпляр CommentId функционально определяет UserId (FD: CommentId -> UserId)
  • Любой данный экземпляр CommentId функционально определяет Score (FD: CommentId -> Score)

Все здесь является зависимым атрибутом для CommentId и CommentId один. Это может привести вас к убеждению, что отношение (таблица), содержащее все или подмножество вышеуказанные атрибуты должны быть нормализованы.

Прежде всего, спросите себя, почему вы все равно создали атрибут CommentId? Строго говоря, это искусственный атрибут - он не имеет отношения к чему-то «реальному». Идентификатор комментария обычно упоминается как суррогатный ключ. Суррогатный ключ - это просто выдуманная ценность, которая стоит в для уникального набора значений, соответствующего некоторой другой группе атрибутов. Так что же это за группа атрибутов CommentId суррогат? Мы можем понять, что задавая следующие вопросы и добавляя новые FD в модель:

  • 1) Должен ли комментарий быть уникальным? Если так, то FD: Comment -> CommentId должно быть истинным.
  • 2) Можно ли сделать один и тот же комментарий несколько раз, если речь идет о другом человеке? Если так, то FD: Person + Comment -> CommentId должно быть true, а FD в 1 выше - false.
  • 3) Можно ли сделать один и тот же комментарий несколько раз в отношении одного и того же лица при условии, что он был сделан другой идентификатор пользователя? Если это так, FD в 1 и 2 не может быть правдой, но FD: Person + Comment + UserId -> CommentId может быть правдой.
  • 4) Можно ли сделать один и тот же комментарий несколько раз в отношении одного и того же лица с помощью одного и того же идентификатора пользователя, но есть разные результаты? Это означает, что FD: Person + Comment + UserId '+ Score -> CommentId верно, а остальные ложно.

Точно один из вышеуказанных 4 FD должен быть верным. В зависимости от того, как это влияет, нормализуется ваша модель данных.

Предположим, FD: Person + Comment + UserId -> CommentId оказывается верным. Логичный последствия таковы:

  • Person + Comment + UserId и CommentId служат эквивалентными ключами по отношению к Score
  • Score следует связать с одним, а не с обоими его ключами (чтобы избежать переходных зависимостей). Очевидным выбором будет CommentId, поскольку он был специально создан как суррогат.
  • Отношение, состоящее из: CommentId, Person, Comment, UserId, необходимо связать Ключ к его суррогату.

С теоретической точки зрения суррогатный ключ CommentId не является требуется, чтобы ваша модель данных или база данных работали. Однако его присутствие может повлиять на построение отношений.

Создание суррогатных ключей является практическим вопросом, имеющим некоторое значение. Подумайте, что может произойти, если вы решите не использовать суррогатный ключ, а полный набор атрибутов Person + Comment + UserId на своем месте, особенно если это было необходимо для нескольких таблиц в качестве внешнего или первичного ключа:

  • Комментарий может добавить много места в вашу базу данных, потому что это повторяется в нескольких таблицах. Это, вероятно, больше, чем пара символов.
  • Что произойдет, если кто-то решит редактировать комментарий? Это изменение необходимо распространять ко всем таблицам, где Комментарий является частью ключа. Не красивое зрелище!
  • Индексирование длинных сложных ключей может занимать много места и / или снижать производительность обновления

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

Теперь вернемся к вопросу о том, следует ли создавать суррогат для Person.Person живет на левой стороне многих или каких-либо FD?Если это произойдет, его значение будет распространяться через вашу базу данных, и есть основания для создания суррогата для него.Является ли Person текстовым или числовым атрибутом, не имеет отношения к выбору создания суррогатного ключа.

Исходя из того, что вы сказали, в лучшем случае есть слабый аргумент для создания суррогата для Person.Этот аргумент основан на подозрении, что его значение в какой-то момент может стать ключом или частью ключа в какой-то момент в будущем.

1 голос
/ 10 сентября 2010

Ну, есть две школы мысли.Один из них гласит: создайте модель данных максимально нормализованным способом, а затем отмените нормализацию, если вам нужна более высокая эффективность.Другой в основном «выполнить минимальную работу, необходимую для работы, а затем изменить ее по мере изменения ваших требований».Также известный как ЯГНИ (Вам это не понадобится).

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

0 голосов
/ 17 марта 2014

С этой базой данных вы можете почувствовать, что это нормально, но в будущем могут возникнуть некоторые проблемы, если вы хотите, чтобы пользователи узнали больше из базы данных. Предположим, вы хотите узнать о количестве комментариев, сделанных к человеку сthe name = 'abc'. В этом случае вам придется просмотреть всю таблицу комментариев и продолжить подсчет. Вместо этого вы можете иметь атрибут count с именем count для каждого человека и увеличивать его всякий раз, когда комментарийсделано для этого человека.
Что касается нормализации, то всегда лучше иметь нормализованную базу данных, потому что она уменьшает избыточность и делает базу данных интуитивно понятной для понимания.Если вы ожидаете, что ваша база данных в будущем станет большой, тогда должна присутствовать нормализация.

0 голосов
/ 18 декабря 2013

Всякий раз, когда вы имеете дело с пользователями, должна быть выделенная таблица. Затем вы можете просто присоединиться к таблицам и обратиться к ID этого пользователя.

user -> id | username | password | email

comment -> id | user_id | content

SQL для присоединения комментариев к пользователям:

SELECT user.username, comment.content FROM user JOIN comment WHERE user.id = comment.user_id;

В будущем это будет намного проще, если вы захотите найти информацию об этом конкретном пользователе. Количество дополнительных усилий незначительно.

Что касается "оценки" для каждого комментария, это также должна быть отдельная таблица. Таким образом, вы можете подключить пользователя к «нравится» или «не нравится».

...