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

У меня есть таблица db с именем Календарь с полями

  • Id (PK)
  • Имя
  • Описание
  • CalendarTypeId (FK в таблицу CalendarType)

У меня есть другая таблица с именем CalendarType с полями

  • Id (PK)
  • Имя
  • Описание

Проблема в том, что мне нужно сохранить дополнительное поле для каждого календаря, где тип календаря - 2. (но это поле не имеет значения для любого другого типа календаря).

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

Ответ 1

Хорошо, это ER-модель того, что у вас есть (отсутствие мощности):

Теперь давайте сосредоточимся на Календаре и SubCalendar. Ясно, что у вас есть иерархия. Но как иерархии превращаются в таблицы? Существует три общих способа сделать это:

1) Убить родителя и сохранить детей. В этом случае вы удаляете родительский объект и отправляете все поля из этого объекта каждому из этих детей. В вашем примере у вас есть только один ребенок, поэтому все родительские атрибуты будут доступны только для него.

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

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

2) Убить детей и сохранить родительский. В этом случае вы удаляете все дочерние элементы и отправляете все свои атрибуты родителям. Поскольку родитель теперь представляет собой смесь самого себя и всех своих детей, ему нужен способ определить, какая строка принадлежит тому типу детей. Это достигается добавлением нового атрибута к родительскому объекту, который будет определять тип каждой строки (независимо от типа данных).

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

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

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

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

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

Теперь вы спросили, какая схема базы данных best. Я думаю, теперь ясно, что это зависит от требований, типов запросов, которые будут выполняться, способа структурирования данных и т.д.

Однако, я могу проанализировать это немного больше. Вы сказали, что у вас есть таблица календаря, и иногда для каждого из них требуется больше данных. Итак, мы можем сказать, что у нас есть 2 типа календарей, родитель и ребенок. Поэтому мы можем подумать, что переход на решение 2 - хорошая возможность, потому что у вас будет 2 строки, представляющие каждый тип, но мы ошибались. Это связано с тем, что в этом случае каждый ребенок включает в себя родителя. Теперь, если мы можем предположить, что если SubAttribute всегда будет непустым для дочернего элемента и null для родителя, мы даже удалим CalendarType, что фактически приведет к решению 1.

Наконец, как правило (главным образом потому, что большинство запросов имеют много объединений в реальной жизни), если вы хотите сосредоточиться на производительности, вы должны пойти на решение 1, в противном случае, если вы хотите сосредоточиться на нормализации вы должны пойти на решение 3.

Надеюсь, это устранило некоторые сомнения и, возможно, вызвало другие:)

Ответ 2

Я бы, вероятно, использовал Calendar. Я называю это перегрузкой таблицы Db. Когда хранение данных было дорогостоящим, это было преступлением. Теперь он назвал решение проблемы простым способом и движением. Никогда не над инженером, пока вам это не понадобится.

Однако вы явно не указали, изменилось ли значение дополнительного поля для каждого экземпляра Календаря с идентификатором типа из 2. Иногда в моих таблицах типов есть поля подтипа и т.д., но я предполагаю, что это случай, когда экземпляры календаря Тип 2 WILL имеют разные значения в требуемом поле.

Ответ 3

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

Это прямо, и, самое главное, легко проверить.

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

Ответ 4

Вы можете использовать шаблон наследования одиночной таблицы, который близок к вашему предложению,

http://martinfowler.com/eaaCatalog/singleTableInheritance.html

или

http://martinfowler.com/eaaCatalog/classTableInheritance.html

если вы хотите специализировать некоторые таблицы для соответствия типам (Calendar и CalendarType2), которые вы пытаетесь представить в своей базе данных

Ответ 5

Леора,

Я бы рекомендовал вам использовать таблицу календаря и null дополнительные поля, которые не требуются для других типов календаря. По мере изменения требований вы сможете добавить дополнительные атрибуты в таблицу календаря таким образом.

Я также рекомендовал бы иметь базовый класс календаря для вашей модели, а затем создавать подклассы, сопоставленные с использованием поля calendartypeid, и использовать определенные подклассы календаря в вашем приложении по мере необходимости. Большинство ORMS будут поддерживать этот тип сопоставления, а также позволят вам сделать каждый подкласс отличным от других, если возникнет необходимость

Стивен