Схема базы данных, которая может поддерживать специализированные свойства - PullRequest
8 голосов
/ 29 ноября 2010

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

Решения

Хранилище данных является реляционной СУБД, и это не для обсуждения :-) В частности, этоMicrosoft SQL Server 2005.

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

ДругойИдея состоит в том, чтобы создать таблицу

reading(<common properties>, extended_properties)

и иметь поле extended_properties, являющееся своего рода сериализацией расширенных свойств.Я думал о JSON или XML.Я, скорее всего, буду использовать каркас ORM, но я еще не решил.В любом случае, объектное представление специализированного объекта из reading может предоставить словарь {extended_property_name, value}, содержащий проанализированные пары ключ / значение из поля extended_properties.

Из этого http://msdn.microsoft.com/en-us/library/ms345117(SQL.90).aspxЯ понимаю, что поля XML в сочетании со схемами для них дают представление о типизированном XML внутри СУБД.Кроме того, запросы, включающие содержимое XML в поле extended_properties, также могут принимать это во внимание.

Что я хочу

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

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

Любая обратная связь очень ценится!

Ответы [ 5 ]

13 голосов
/ 05 декабря 2010

Андерс, не отказывайся ни от какой целостности или твердости, например, от типа безопасности.

(Ответ приходит).

@ Андерс.Нет, совсем нет, подтип - это хорошо (вопрос в том, какую форму вы используете и каковы недостатки / преимущества).Не отказывайтесь ни от силы, ни от целостности, ни от безопасности, ни от проверок, ни от DRI.Форма, которую вы выберете, потребует дополнительных проверок и, возможно, небольшого количества кода (зависит от вашей платформы).

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

Предупреждение: только для опытных инженеров-строителей
Дорога не подходит для караванов или читателей с высоким коэффициентом Eek

Ссылка на ▶ Четыре альтернативных модели данных ◀ в Документе в стадии разработки.Извиняюсь за беспорядок на полу;Я скоро уберусь.

▶ Ссылка на нотацию IDEF1X ◀ для всех, кто не знаком со Стандартом моделирования реляционных баз данных.

  1. Все они реляционные, с полной целостностью.

  2. Опции 6NF.Реляционный сегодня (SQL) не обеспечивает поддержку 6NF;он не запрещает этого, он просто не предоставляет структуры 5NF➔6NF.Поэтому вам нужно создать небольшой каталог, который некоторые люди называют «метаданными».На самом деле, это просто расширение стандартного каталога SQL (таблицы sys).Требуемый уровень контроля моделируется в каждой опции.

  3. По существу, EAV выполнен правильно, с полным контролем и целостностью (безопасность типов, декларативная ссылочная целостность и т. Д.), А не беспорядком, которым он обычно является.

Вас могут заинтересовать эти связанные вопросы / ответы (в частности, посмотрите на Модели данных):

Несколько фиксированных и абстрактныхГибкая

Проблема, связанная со схемой базы данных

«Простая» проблема проектирования базы данных

Ответ на комментарии

... Таким образом, мы можем легко получить строки «Комментарий», связанные с данным экземпляром специализированного типа.Это способ сделать это, или я буду сожалеть об этом решении позже?Есть ли какой-то другой шаблон, который мы пропустили?

Не уверен, что вы имеете в виду.Комментарии, заметки, адреса в конечном итоге используются (резидентные столбцы) во многих таблицах, поэтому правильный метод - нормализовать их;предоставить одну таблицу для комментариев;на который ссылаются из любой таблицы, которая требует этого.Вот общая таблица комментариев.Он используется в Product (супертип), потому что вы указали любой Product.С таким же успехом его можно использовать в некоторых подтипах Product, но не в других;в этом случае FK будет в указанных подтипах продукта.

Ваша модель данных

Какова цельтаблицу ProductType в вашем примере Product 5NF / subtype?Содержит ли он строку, соответствующую каждому специализированному продукту, например ProductCPU?Я предполагаю, что это указывает на специализацию базового продукта.

(Исправлена ​​небольшая критическая ошибка в диаграмме.)

Да, точно.

В стандартных терминах отношений (не неконтролируемые беспорядки, выдаваемые за базы данных), ProductType является Discriminator ;он определяет, какой из подтипов продукта применяется к данному продукту.Сообщает вам, к какой таблице подтипа продукта нужно присоединиться.Пара вместе составляет логичный продукт.Не забудьте создать представления, по одному для каждого типа продукта.

  • (Оцените, как изменяется ProductType, какую именно роль он играет, для каждой из четырех моделей данных.)

  • «Обобщение-специализация» - все термины mumbo jumbo, OO; не переступая черту и не узнавая, на что способен Relational в течение 30 лет. Если вы немного узнаете о Реляционном, вы получите полную силу; в противном случае вы ограничены очень ограниченным подходом ОО ко всему (Амблер и Фаулер могут многое ответить). Пожалуйста, прочитайте этот пост , начиная с 11 декабря 10 и далее. Модель реляционных баз данных Сущности, а не объекты; не классы.

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

Да. И какую страницу (с полями) предоставить пользователю для ввода данных.

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

  • Для ваших классов OO сопоставьте дерево классов с Rdb, как только вы закончили моделирование Rdb, независимо от приложения, которое будет его использовать. А не наоборот. И не зависит от одного приложения.

  • Забудьте о «сохранении», у него много проблем (Потерянные обновления; нарушена целостность данных; проблемная отладка; массовая конкуренция и т. Д.) Все обновления Rdb должны быть в Транзакциях, с соответствием ACID, доступным в течение 30 лет, но Фаулер и Амблер еще не читали об этом. Обычно это означает, что один сохраненный процесс пре-факт.

Дискриминант представляет собой FK таблицы типов, как мы установили ранее. Он обозначает подтип spec. , которого придерживается базовый тип. Но что подробно содержит таблица дискриминантов?

Разве это не ясно из модели данных? ProducType CHAR(1) или (2). Name Char(30).

Может быть текст, удобный для отображения с указанием типа для целей пользовательского интерфейса,

Да, среди прочего, такие как контроль, противопоказания и т. Д., Устранение двусмысленности при кодировании или отчетности.

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

Нет. Это было бы слишком физически для размещения в данных. Запрещено в принципе.

Но это не обязательно.

Скажите, что меня интересует Продукт с ID = 1. У него есть дискриминант, указывающий, что это ProductCPU. Как вы будете извлекать этот ProductCPU из кода вашего приложения?

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

  • с учетом ProductId (подтип неизвестен, поэтому вы не должны находиться в окне, относящемся к подтипу), загрузить Product только супертип
  • на основе Дискриминатора Product.ProductType, установки индикаторов и т. Д. И загрузки соответствующего подтипа, одного из ProductCPU; ProductMemory; ProductDisk; ProductTape; и т.д.

  • Я видел (и не согласен с) ОО-методы, которые загружают все подтипы для данного ProductId одновременно: один подтип является допустимым; а остальные недействительны. Код все еще должен ограничиваться допустимым классом для Product на основе Product.ProductType.

Альтернативно, например. где контекст, пользователь сидит в специфичном для подтипа окне, например. ProductCPU, с настройкой этого класса и запросами ProductId xxx. Затем используйте ProductCPU View. Если он возвращает ноль строк, он не существует.

  • Может быть ProductDisk xxx, но не ProductCPU xxx. Как вы справитесь с этим, независимо от того, указываете ли вы на наличие Product`xxx, но это не ЦП или нет, зависит от требований приложения.

Для списков, где приложение заполняет сетку, независимо от ProductId, используйте представления (по одному на каждом), чтобы загрузить каждую сетку. Этот SQL основан на объединении и не должен ссылаться на ProductType.

1 голос
/ 30 ноября 2010

Это классический пример шаблона проектирования Gen-Spec. Gen-spec рассматривается в каждом руководстве по моделированию объектов, потому что оно обрабатывается наследованием. Это часто пропускается в руководствах по моделированию реляционных данных. Но это хорошо понято.

Проведите веб-исследование на тему "Обобщение специализации реляционного моделирования". Вы увидите несколько статей о том, как настроить одну таблицу для общего класса и таблицу для каждого специализированного класса. Статьи помогут вам с дизайном внешнего ключа. В частности, первичный ключ каждой специализированной таблицы выполняет двойную функцию. Это также внешний ключ к обобщенной таблице.

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

1 голос
/ 29 ноября 2010

Я бы лично выбрал метод «создать таблицу для общих свойств, а затем таблицу для каждой из специализированных версий».

Причина: вы говорите, что ваша реализация будет выполнена в СУБДи это не подлежит обсуждению.Хорошо.Вывод неструктурированных, похожих на блоб объектов, таких как сериализованная хэш-таблица в поле БД, противоречит философии проектирования СУБД, поэтому вы сильно пострадаете от эффективности, если не согласитесь с идеей рассматривать поле * extended_properties * как непрозрачноеblob, точно так же, как gif или другой двоичный объект.

Другими словами, забудьте (эффективно) запрашивать «все объекты, имеющие расширенное свойство COLOR = RED».

Ваша проблема (описание ОО-таксономий в СУБД) определенно не нова.Взгляните на this , чтобы получить подробное описание опций.

0 голосов
/ 29 ноября 2010

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

В общем, я бы не советовал сериализовать данные в поля БД.Вы можете просто использовать подтип, как в следующих примерах: пример один , пример два .

Длябольшие значения свойств или если свойства должны быть определены динамически (без изменений схемы), посмотрите на реализацию схемы наблюдения, как в следующих примерах: пример три , пример четыре ;или в так называемую шестую нормальную форму, как описано в: пример пять .Обратите внимание, что «схема наблюдения» является упрощенной версией 6-й НФ.

0 голосов
/ 29 ноября 2010

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

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

Unique_Property_ID
, FK_To_Some_Entity (Not sure what entity these link to: customers, bills, etc.) 
, Property_Type Not the data type but a link to a table describing this entity)
, Property_Value (Difficult to determine if all of your values will be of the same type: string, int, date, etc.)

Пример: автосалон подержанных автомобилей, которому нужно отслеживать надстройки для разных марок и моделей (они никогда не знают, что получат),Несколько записей могут выглядеть так:

VehicleID   Property Type  Property Value
3           Sound System   Bose
3           Hybrid System  Battery
7           Starter Type   Hand Crank
7           Passenger Seat Rumble
9           Starter Type   Kick Start
9           Passenger Seat Side Car

Каждое значение для каждого Set |Тип свойства будет иметь свою собственную запись.

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

...