Плохо ли иметь несколько взаимоисключающих взаимно-однозначных отношений?

38

Скажем, таблица carимеет один-к-одному отношение к таблицам electric_car, gas_carи hybrid_car. Если carесть electric_car, то больше не может появляться в gas_carили hybrid_carи т.д.

Что-то не так с таким дизайном? Некоторые проблемы, которые могут возникнуть в будущем?

Артур Тарасов
источник

Ответы:

59

Различные типы автомобилей являются примером общей проблемы, которая снова и снова появляется при моделировании данных. Это называется «обобщение / специализация» в моделировании ER и «суперкласс / подкласс» в моделировании объектов.

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

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

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

Это простое решение хорошо работает для небольших и простых случаев. Наличие большого количества NULL добавляет незначительные издержки к хранилищу и немного к накладным расходам на поиск. Разработчику, возможно, придется изучить трехзначную логику SQL, если булевы тесты выполняются на обнуляемых столбцах. Сначала это может сбить с толку, но к этому привыкаешь.

Существует еще один метод, называемый наследованием таблиц классов . В этом проекте есть отдельные таблицы для gas_car, electric_car и hybrid_car, в дополнение к комбинированной таблице car для всех из них. Когда вы хотите получить все данные об определенном типе автомобиля, вы присоединяете таблицу автомобилей к соответствующей специализированной таблице. В этом дизайне меньше NULL, но вы больше присоединяетесь. Этот метод работает лучше в больших и более сложных случаях.

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

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

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

Уолтер Митти
источник
3
Ух ты, спасибо! Это то, что я пытался выяснить. Наследование таблиц классов, кажется, именно то, что мне нужно. Я изменил свой принятый ответ на этот вопрос для будущих читателей, так как думаю, что он полностью охватывает вопрос, а не только мой случай.
Артур Тарасов
6
Отличный ответ здесь. Один совет: тщательно документируйте эти дизайнерские решения. Какой бы путь вы ни выбрали, он не будет очевиден, когда кто-то исследует структуру базы данных. Некоторые базы данных, такие как Postgres, позволяют вам связать комментарий с метаданными ваших столбцов, таблиц и тому подобного.
Василий Бурк
Вы не рассматриваете ограничение на то, чтобы не допустить, чтобы электромобили также были гибридными. Вам нужен отдельный стол для этого.
Jmoreno
2
Вы правы. Если вы добавите поле car_type в таблицу cars, вы можете ограничить принадлежность автомобилей только одним типом за счет отклонения от полной нормализации. Хорошая СУБД позволит вам определить проверочное ограничение, которое не позволит вписать автомобиль в более чем одну специализированную таблицу. В этом есть некоторые издержки, вы идете, чтобы добавить новые автомобили.
Уолтер Митти
@WalterMitty, но без car_typeполя, как узнать, какую таблицу нужно искать для получения данных при получении данных? Нужно ли читать все три таблицы, чтобы узнать, в какой из них есть данные об этой конкретной carзаписи?
Джош Часть
12

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

Например, по вашему примеру, что вы делаете с чем-то вроде Audi A4 eTron - который представляет собой плагин-гибрид? Это "электрический автомобиль" или "гибридный автомобиль"?

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

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

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

Джоэл Браун
источник
Спасибо, я боялась, что устанавливаю для себя какую-то ловушку. Моя проблема в том, что у каждого из подтипов будет много столбцов. Некоторые будут перекрываться, и я положу их в carтаблицу, но многие не будут и будут помещены в таблицу подтипов. Например, это будет что-то вроде хранения элементарных частей типов автомобилей. Двигатель электромобиля может иметь как 100 частей, так и бензиновый двигатель 75 частей, а гибридный 125 частей. 50 частей будут общими и храниться в cars, в то время как 50, 25 и 75 будет electric_car, gas_carи hybrid_carстолы
Артур Тарасы