Пример оформления таблицы базы данных с сомнительной повторяющейся группой - PullRequest
1 голос
/ 01 декабря 2009

Я обсуждаю с кем-то следующую таблицу, которая используется для связи элементов, специфичных для клиента:

Table LINK:

Client (int) 
Item1 (int) 
Item2 (int)

Это спорный дизайн. Все три поля относятся к другим таблицам. Два поля Item относятся к одной и той же таблице. Это не настоящие имена полей, поэтому не беспокойтесь о обсуждении соглашений об именах (однако «1» и «2» действительно являются частью имени поля). Я утверждаю, что этот дизайн является плохим по причине нарушения 1NF, в то время как другой человек утверждает, что, хотя это кажется неприятным, все другие варианты хуже для нашего конкретного варианта использования.

Примечания:

  • В подавляющем большинстве случаев требуется только связать два элемента друг с другом;
  • N: 1 группы разрешены; в таком случае один и тот же Item1 повторяется на нескольких строках с разными значениями Item2;
  • Существует также очень небольшое количество случаев, когда некоторые значения Item2 (в существующих ссылках Item1-Item2) сами связаны с другими Предметами, и в этих случаях эти значения появляются в столбце Item1, а другое связанное значение в столбец Item2; все связанные элементы соответствуют одной группе и должны быть извлечены как таковые.

Мои претензии:

  • Это нарушает 1NF: Item1 и Item2 являются внешними ключами для той же таблицы и, как таковые, составляют повторяющуюся группу (другая сторона не согласна с определением повторяющейся группы);
  • Для поиска в Item это означает, что вместо одного требуется два индекса, например, в таблице, в которой вместо этого используется поле GroupID;
  • Это усложняет запросы на поиск конкретного элемента в этой таблице, потому что условие ограничения должно проверять поля Item1 и Item2.
  • Поиск для случая, когда встречаются цепочки ссылок Item, будет более сложным.

Другая сторона заявляет:

  • Наиболее жизнеспособной альтернативой является таблица с одним полем Item и дополнительным полем GroupID;
  • Более простой, более распространенный случай ссылки из двух элементов теперь становится более сложным;
  • При получении слотов GroupID могут возникнуть проблемы с параллелизмом, и этим нужно управлять
  • Для управления проблемами параллелизма GroupID, вероятно, требуется вторая таблица с GroupID в поле с ограничением уникальности
  • Теперь вам нужно выполнить объединение, по крайней мере, некоторое время, особенно если используется ORM. Объединение менее эффективно, чем использование одной таблицы, как в текущем проекте.

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

РЕДАКТИРОВАТЬ 1:

  • Item1 и Item2 являются (финансовыми) транзакциями
  • «1» и «2» действительно являются частью имени поля

Ответы [ 2 ]

2 голосов
/ 01 декабря 2009

Что такое Item1 и Item2? Они разные объекты? Тогда дизайн мне кажется подходящим.

Например, вы можете заполнить базу данных решениями проблемы коммивояжера. У вас есть таблица City (cityId, широта, долгота) и путь к таблице (pathId, salesmanId). Теперь путь, по которому продавец посещает n + 1 городов, будет представлен n записями в PathSegment (pathId ,gmentId, fromCityId, toCityId). Здесь, хотя fromCityId и toCityId являются внешними ключами, которые ссылаются на одну и ту же таблицу City, они описывают различные атрибуты сущности PathSegment, поэтому это не нарушает NF1.

Edit:

То есть вы хотите хранить деревья, на самом деле, только ваши деревья в основном являются связанными списками, и большинство из них являются связанными списками с двумя узлами, верно? И, очевидно, ваш коллега хочет сделать это как список смежности, так что дерево, как

1-2-3
\-4

становится

(1,2)
(2,3)
(1,4)

В этом нет ничего плохого, но это не единственный способ сохранить дерево в базе данных. Для хорошего резюме альтернатив, см. Здесь .

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

select item1 from link where item2 = :paymentID

что тоже неплохо. Однако есть и недостатки. Порядок дочерних узлов часто имеет значение, и этот список здесь вам не поможет, поэтому вы должны хранить его как отдельный столбец или как что-то вроде меток времени в таблицах, на которые ссылаются ваши внешние ключи). Кроме того, восстановление всей ветви становится рекурсивной задачей, и не все системы баз данных могут это сделать. Таким образом, если вашему приложению часто приходится получать обзор истории счетов, похожий на доску объявлений, ему может потребоваться некоторая логика на стороне приложения, которая превращает список соседних узлов в дерево на клиенте и работает на этом. Если это становится слишком громоздким, вы можете рассмотреть представление вложенных множеств, см. Здесь .

Что лучше для вашей проблемы? Зависит от нескольких вещей: размер и форма ваших деревьев (если они действительно в основном короткие связанные списки, список смежности хорош), частота вставок и обновлений (если часто, список смежности хорош, потому что его вставки дешевы), частота и сложность запросов (если частые и сложные, вложенные множества хороши, потому что их выбор прост и быстр). Так что для доски объявлений я бы использовал вложенные наборы (или даже Tropashkos вложенные интервалы для скорости и дополнительной крутости), но для простой таблицы «запрос-ответ» (а иногда и больше ответов), я Возможно, я буду использовать список смежности.

1 голос
/ 01 декабря 2009

Наличие двух внешних ключей, указывающих на одну и ту же таблицу, по умолчанию не является "нарушением". Возможно, у вас есть таблица Person с полями FatherID и MotherID, указывающими на таблицу Person. Это не повторяющаяся группа, так как они семантически разные атрибуты. Ваша первая претензия & mdash; написана и свободна от других контекстов & mdash; неверна

...