Полиморфные отношения против отдельных таблиц для каждого типа - PullRequest
2 голосов
/ 23 июня 2019

Я работаю с базой данных, которая имеет несколько типов (например, User, Appointment, Task и т. Д.), Которые могут иметь ноль или более Notes, связанных с каждым типом.

Возможные решения для реализации этих отношений:

  1. Полиморфная связь
  2. Отдельная таблица для каждого типа

Полиморфная связь

Многие считают, что это самое простое решение для реализации и, по-видимому, наиболее распространенная реализация для сред, которые следуют шаблону Active Record, я бы добавил таблицу, данные которой morphable:

notable

Мой notable_type позволил бы мне различать тип (User, Appointment, Task), к которому относится Note, тогда как notable_id позволил бы мне получитьотдельная запись type в соответствующей таблице type.

PROS:

  • Легко масштабируется, больше моделей можно легко связать с полиморфнойкласс
  • Пределы таблицы раздувания
  • Результаты в одном классе, который может использоваться многими другими классами (СУХОЙ)

CONS

  • Больше типов может усложнить запрос идороже по мере роста данных
  • Не может иметь внешний ключ
  • Отсутствие согласованности данных

Отдельная таблица для каждого типа

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

user notes

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

PROS:

  • Позволяет нам эффективно использовать внешние ключи
  • Эффективный запрос данных
  • Поддерживает согласованность данных

CONS:

  • Увеличивает раздувание таблицы, поскольку для каждого типа требуется отдельная таблица
  • Результатов становится несколько классов, каждый из которых представляет отдельную type_notes таблицу

Мысли

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

Таблица на отношение notes (user_notes, task_notes и т. д.) с внешними ключами кажетсяверным способом (в соответствии с шаблонами проектирования), но может привести к множеству таблиц (добавление других types, которые могут иметь notes или добавление типов, подобных notes [например, events]).

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

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

Ответы [ 2 ]

3 голосов
/ 23 июня 2019

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

Если вы хотите добавить несколько таблиц, то почему у вас есть отдельные таблицы для UserAppointment и Task?Если бы у вас был многозначный атрибут для User, например, для нескольких телефонных номеров на пользователя, вы бы создали отдельную таблицу для телефонов или попытались бы как-то объединить их все в пользовательскую таблицу?Или иметь полиморфную таблицу «вещи, которые принадлежат другим вещам» для пользовательских телефонов, приглашенных на встречу и этапов задачи?

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

Правильнее всего делать моделирование таблиц базы данных так же, как моделирование типов объектов в приложении.Возможно, вам захочется прочитать книгу типа SQL и реляционная теория: как написать точный код SQL, 3-е издание, CJ Date , чтобы узнать больше о том, как таблицы аналогичны типам.

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

Если вам нужно создать одну таблицу примечаний, вы можете сделать так, чтобы она ссылалась на одну таблицу с именем "Известный ", который похож на суперкласс User, Appointment и Task.Тогда каждая из этих трех таблиц также будет ссылаться на первичный ключ Notable.Это имитирует объектно-ориентированную структуру полиморфизма, где у класса Note есть ссылка на объект по его типу суперкласса.

Но ИМХО, это сложнее, чем нужно.Я бы просто создал отдельные таблицы для UserNotes, AppointmentNotes и TaskNotes.Меня не беспокоит наличие еще трех таблиц, и это делает ваш код более понятным и понятным.

1 голос
/ 23 июня 2019

Я думаю, вам следует подумать об этих двух вещах, прежде чем вы сможете принять решение.

  1. Производительность. много читает, много пишет? Тест, который лучше.
  2. Рост вашей модели. Можно ли его легко расширить?
...