Противоречивые желания в дизайне базы данных, с полями двух похожих функций - PullRequest
0 голосов
/ 22 сентября 2008

Хорошо, я сейчас готовлю таблицу для "Коробок".

Теперь элемент ящика, в зависимости от того, для чего он используется / статус предмета, может в конечном итоге быть связан с ящиком «Доставка» или ящиком «Возврат».

Элемент Box может быть неисправен: если это так, в строке Элемента Box будет установлен флаг (IsDefective), а Элемент Box будет помещен в поле «Returns» (с другими элементами, которые должны быть возвращены этому поставщик). В противном случае, элемент Коробки в конечном итоге будет помещен в коробку «Доставка» (вместе с другими отправляемыми элементами). (Обратите внимание, что у ящиков «Доставка» и «Возврат» есть свои собственные таблицы: для всех ящиков не существует одной общей таблицы ... хотя, возможно, я должен рассмотреть возможность сделать это, если это возможно, в качестве третьей возможности?)

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

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

BoxItemID Описание IsDefective ShippingBoxID ReturnBoxID и т.д ...

Это прояснит отношения, но кажется расточительным (поскольку в любой момент будет использоваться только одно из отношений). Тогда я подумал, что мог бы иметь только одно поле для BoxID и определить, на какой BoxID он ссылается (идентификатор отправления или возврата) на основе поля IsDefective:

BoxItemID Описание IsDefective BoxID и т.д ...

Это кажется менее расточительным, но не подходит мне. Отношение не очевидно.

Итак, я поставлю это перед вами, гуру баз данных Stackoverflow. Что бы вы сделали в этой ситуации?

РЕДАКТИРОВАТЬ: Спасибо всем за ваш вклад! Это дает мне много думать. Во-первых, я собираюсь использовать ORM в следующий раз, когда начну такой проект. =) На двоих, так как я не сейчас, я укушу четыре байта и использую два поля.

Еще раз всем спасибо!

Ответы [ 7 ]

2 голосов
/ 22 сентября 2008

Я с Психотическим Ядом и Матлантом.

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

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

«Преждевременная оптимизация - корень всего зла» и все такое. Хотя это кажется расточительным, помните, что вы храните. Поскольку они являются идентификаторами, они, вероятно, просто целые числа, может быть, 4 байта. Потеря четырех байтов на запись - в принципе ничего. Фактически, из-за заполнения, чтобы поместить вещи на четные адреса или другие подобные вещи, это может быть «свободно», чтобы поместить это дополнительное поле туда. Все зависит от дизайна БД.

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

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

1 голос
/ 22 сентября 2008

Я бы использовал то, что Hibernate называет Таблица на подкласс , поэтому моя БД получит 3 таблицы для ящиков: Box, ShippingBox и ReturnBox. ФК в BoxItem будет указывать на Box.

1 голос
/ 22 сентября 2008

Я бы рассмотрел создание одной таблицы для блоков, а тип блока - это столбец таблицы блоков. Это упростит отношения и упростит возможность запроса типа блока. Таким образом, элемент box имеет только один внешний ключ для boxId.

1 голос
/ 22 сентября 2008

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

А как насчет этого?

BoxItem:
BoxItemID, Description, IsDefective

Box:
BoxID, Description

BoxItemMap:
BoxID, BoxItemID, BoxItemType

Тогда BoxItemType может быть перечислением или целым числом, в котором вы определяете константы в вашем приложении как «Возврат» или «Доставка» как тип поля.

0 голосов
/ 22 сентября 2008

Я бы выбрал только одну таблицу BoxItems с IsDefective, ShippingBoxID, полями, относящимися к отправке, ReturnBoxID и полями, возвращаемыми. Некоторые поля всегда будут NULL для каждой записи.

Это очень простой и очевидный дизайн, который вряд ли будет смущен следующим разработчиком. Теоретически такой дизайн неэффективен из-за гарантированных пустых полей для каждой строки. На практике базы данных, как правило, имеют минимальный требуемый размер хранилища для каждой строки в любом случае, поэтому (если количество полей не очень велико), эта схема в любом случае максимально эффективна, и ее гораздо проще кодировать.

0 голосов
/ 22 сентября 2008

Я бы, наверное, пошел с:

BoxTable:
box_id, box_descrip, box_status_id ...
     1, Lovely Box, 1
     2, Borked box, 2
     3, Ugly Box, 3
     4, Flammable Box, 4

       BoxStatus:
       box_status_id, box_status_name, box_type_id, ....
                   1,Shippable, 1
                   2,Return, 2
                   3,Ugly, 2
                   4,Dangerous,3

                BoxType:
                box_type_id, box_type_name, ...
                          1, Shipping box, ...
                          2, Return box, ....
                          3, Hazmat box, ...

Таким образом, «Состояние ящика» определяет тип ящика, и он гибок, если позже вам понадобится расширить на несколько уровней статуса или типов ящика.

0 голосов
/ 22 сентября 2008

Согласитесь, о полиморфном обсуждении выше, хотя оно потенциально может быть использовано плохо, но оно все еще остается жизнеспособным решением

В основном у вас есть базовая таблица с названием box. Тогда у вас есть две другие таблицы, упаковочная коробка и возвратная коробка. Эти два добавляют любые дополнительные поля, которые являются особенными для них. они связаны с ящиком с базовой таблицей 1: 1 fk.Boz и имеют общие поля для всех типов ящиков.

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

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

Практически все ORM поддерживают эту стратегию.

...