Вопрос проектирования базы данных SQL - PullRequest
3 голосов
/ 05 августа 2009

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

Допустим, у меня есть четыре таблицы: Equipment, CurrentState, StateValue, StateType со следующими схемами:

Equipment
------------
Id (PK),
Name


CurrentState
------------
Id (PK),
EquipmentId (FK) (IX),
StateValueId (FK),
StateTypeId (FK) (IX)


StateValue
------------
Id (PK),
StateTypeId (FK),
Name


StateType
-----------
Id (PK),
Name

У единицы оборудования может быть несколько разных CurrentStates, принадлежащих к различным StateTypes, следовательно, Уникальный индекс (IX). StateType - это в основном конечный автомат, а StateValue содержит значения для каждого конечного автомата.

Теперь мой вопрос, а именно 2 вопроса, касается внешних ключей StateTypeId в таблицах CurrentState и StateValue, которые определяют, какой StateType является записью CurrentState и чем StateType является запись StateValue.

Прежде всего, имеет ли этот тип отношений плохой дизайн с точки зрения ссылочной целостности? Я предполагаю, что это плохой дизайн, так как между таблицей CurrentState и таблицей StateType должна быть только одна ссылка, и это происходит через StateValue, в противном случае запись CurrentState может в итоге иметь два разных StateTypes (один через прямой FK и другое через таблицы StateValue FK) ...

Но возникает второй вопрос: если у меня не должно быть StateTypeId FK в таблице CurrentState, как я могу применить Index, то есть убедиться, что не существует двух записей CurrentState для одного EquipmentId, у которых StateValueIds указывает на записи StateValue того же StateType ...

Нужно ли использовать триггер при вставке в таблицу CurrentState для проверки соблюдения правил? Я никогда раньше не использовал триггеры, поэтому мне нужно будет немного изучить. Я также использую Entity Framework и понятия не имею, как это повлияет (в теории не должно быть).

Ответы [ 4 ]

2 голосов
/ 05 августа 2009

Да, это плохая практика, поскольку вы можете иметь два разных типа состояний для одного текущего значения. Удалите столбец StateTypeId из CurrentState, и он будет проходить только через StateValueId. Ваш уникальный индекс должен быть на CurrentState и StateValueId.

Конечно, если вы настаивали на StateTypeId в CurrentState, вы могли бы установить ограничение check, которое бы обеспечивало равенство StateTypeId с StateTypeId из StateValueId. Но это действительно окольный путь. Гораздо чище и удобнее оставлять их в своих бункерах.

0 голосов
/ 06 августа 2009

То же самое, что FK для StateTypeID ничего не выполняет и создает возможность несовместимых данных.

Я понимаю, что вы пытаетесь упростить задачу для обсуждения, но что это за разные "типы состояний"? Если они не имеют никакого отношения друг к другу, может быть, забить их всех за один стол - плохая идея. Например, если у вас есть тип Location со значениями «Building 1», «Building 2» и «Building 3»; и тип метода амортизации со значениями «30-летняя прямая», «15-летний убывающий баланс» и т. д .; и тип «Требуется техническое обслуживание» со значениями «нет», «полный капитальный ремонт», «настройка» и т. д .; тогда забивать все эти несвязанные вещи в один стол просто неправильно. Если вы создадите отдельную таблицу для каждого типа состояния и отдельный столбец в таблице Equipment для каждого stateValueId, тогда вся проблема исчезнет.

Многое зависит от того, какие запросы вы делаете или, вероятно, будете делать. Есть ли у вас какие-либо запросы, которые упрощены этой структурой таблицы? Или все они усложнены, потому что вы должны проверить и тип состояния, и значение состояния?

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

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

0 голосов
/ 05 августа 2009

Основываясь на ответе Уолтера Митти, я бы сделал еще один шаг вперед: если предположить, что два StateValue, принадлежащие к одному и тому же StateType (т. Е. Имеющие одинаковый StateTypeId), не могут иметь одинаковое имя, я бы отбросил столбец Id в StateValue и взял бы (StateTypeId, name) как составной / составной первичный ключ для StateValue. StateValueId в таблице CurrentState затем заменяется StateValueName, и пара (StateTypeId, StateValueName) в CurrentState ссылается на составной первичный ключ StateValue. Необходимо добавить ограничение уникальности для пары (EquipmentId, StateTypeId) в CurrentState, как описано Уолтером. Если эта пара также используется в качестве первичного ключа для CurrentState вместо Id, зависит от того, ссылаются ли другие таблицы на таблицу CurrentState или нет.

Итак, ответы таковы: 1) Да, 2) Не обязательно

Общий совет: «Начало разработки базы данных» Клэр Черчер (и основанная на ней «Прикладная математика для специалистов по базам данных») - отличное чтение. Вы также можете взглянуть на это в Google Книгах.

0 голосов
/ 05 августа 2009

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

Вам нужно установить составное ссылочное ограничение между CurrentState и StateValue и удалить ссылочное ограничение между CurrentState и StateType. (Я не вижу этого ограничения в вашей постановке задачи, но я предполагаю, что вы используете "FK".) Я забыл синтаксис составного ссылочного ограничения (это может быть специфично для СУБД), но это что-то вроде

CONSTRAINT ValidState FOREIGNKEY (StateValueId, StateTypeId) ССЫЛКИ StateValue (Id, StateTypeId)

Это будет в определении CurrentState. Не беспокойтесь о том, что CurrentState не ссылается на StateType. Поскольку StateValue ссылается на StateType, ваши ограничения будут работать транзитивно вместе. Составное противоречие гарантирует, что вы не сохраните отношения между значениями состояния и типами состояний в текущем состоянии, что противоречит тем же отношениям, которые хранятся в StateValue.

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

СОЗДАТЬ УНИКАЛЬНЫЙ ИНДЕКС CurrentStateIDX для CurrentState (EquipmentId, StateTypeId).

Если бы я занимался дизайном, я бы полностью отбросил столбец CurrentState.ID. Затем я бы определил составной первичный ключ для CurrentState, в котором перечислены EquipmentID и StateTypeID. Это приведет к тому, что СУБД (в большинстве случаев) организует таблицу оптимально для объединений и создаст соответствующий уникальный индекс. В любом случае CurrentState.ID будет редко использоваться. Но если вам действительно нравится иметь столбец идентификатора на каждой таблице, подойдите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...