Плохая практика использования внешнего ключа, допускающего обнуление?


114

Допустим, у вас есть таблица Orders с внешним ключом для идентификатора клиента. Теперь предположим, что вы хотите добавить Заказ без идентификатора клиента (может ли это быть возможным - другой вопрос), вам придется сделать внешний ключ NULL ... Это плохая практика, или вы бы предпочли работать с таблицей ссылок между Заказы и клиенты? Хотя отношение 1 к n, таблица ссылок сделает его n к n. С другой стороны, с таблицей ссылок у меня больше нет этих NULL ...

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

(В моем случае это не Заказ, а Заказчик).

РЕДАКТИРОВАТЬ: Как насчет неназначенного клиента, на который нужно ссылаться?


9
Это одна из основных целей наличия NULL в схеме базы данных. Более того, именно поэтому вы можете объявлять поля NULL или NOT NULL, чтобы можно было удовлетворить конкретные требования вашей схемы.
gahooa

7
Сначала я прочитал вопрос как обнуляемые первичные ключи и собирался перейти к некоторым серьезным советам ... :-)
Анджей Дойл

Ответы:


51

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

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


2
source__destination_link или SourceDestination
Svisstack

7
Мне было бы интересно услышать о ситуации, когда лучше иметь таблицу ссылок, я никогда не сталкивался с ситуацией, когда это каким-либо образом улучшило бы поток процесса.
Reimius

5
Как указано в моем ответе, я был бы прагматичным в этом конкретном случае и не использовал бы таблицу ссылок. Я уверен, что обычные формы были изобретены не для улучшения процесса, а для обеспечения согласованности и исключения дублирования. Тем не менее, это очень общая дискуссия, и я думаю, что ее нужно рассматривать в индивидуальном порядке.
Патрик Хэгне

110

Нет Нет ничего плохого в Nullable FKs. Это обычное явление, когда объект, на который указывает FK, находится в отношении (ноль или один) к (1 или нескольким) с таблицей, на которую ссылается первичный ключ.

Примером может быть, если у вас есть и физический адрес, и атрибут (столбец) почтового адреса в таблице с FK для таблицы адресов. Вы можете сделать Физический адрес допускающим значение NULL для обработки, когда у объекта есть только почтовый ящик (почтовый адрес), и почтовый адрес, допускающий значение NULL для обработки, когда почтовый адрес совпадает с физическим адресом (или нет).


39

Обнуляемые столбцы могут быть от 1 до 5, но не в 6, согласно тому, что я читал.

Только если вы лучше Криса Дейта знаете, «что на самом деле означает первая нормальная форма». Если x и y оба допускают значение NULL, и действительно в некоторой строке x и y оба null, то WHERE x=yне уступает true. Это вне всяких разумных сомнений доказывает, что null не является значением (потому что любое реальное значение всегда равно самому себе). И поскольку RM предписывает, что «в каждой ячейке таблицы должно быть значение», любая вещь, которая может содержать нули, не является реляционной вещью, и поэтому вопрос о 1NF даже не возникает.

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

См. Выше обоснованную причину этого аргумента.

Но на практике это очень практично.

Только если вы невосприимчивы к головным болям, которые они обычно вызывают во всем остальном мире. Одна из таких головных болей (и она лишь незначительная по сравнению с другими nullявлениями) заключается в том, что WHERE x=yв SQL фактически означаетWHERE x is not null and y is not null and x=y , но большинство программистов просто не знают об этом факте и просто читают его. Иногда без вреда, иногда - нет.

Фактически, столбцы, допускающие значение NULL, нарушают одно из самых фундаментальных правил проектирования базы данных: не объединяйте отдельные информационные элементы в один столбец. Нулевые значения делают именно это, потому что они объединяют логическое значение «это поле действительно присутствует / нет» с фактическим значением.


18
+1 для «ГДЕ x не равно нулю и y не равно нулю и x = y». Не знал об этом.
RobM

1
Очень красиво изложены аргументы и примеры.
pedz

1
Одна проблема. Когда значение «не существует» (что ЯВЛЯЕТСЯ реальным сценарием) и атрибут базы данных не допускает нулей, любое значение в атрибуте НЕПРАВИЛЬНО. Что касается головной боли, помните, KISS, это не просто означает, что все должно быть просто, это означает, что все должно быть как можно проще, но не проще. Если «реляционная модель» требует нереалистичного, глупого результата, то, возможно, правила нужно расширить, чтобы они могли обрабатывать необходимые данные из реального мира?
Чарльз Бретана

1
Было показано , что три-значной логики приводит к необходимости четыре-значной логики, что приводит к необходимости пять-значной логики, и т.д. и т.п. 2-значной логики является достаточным, но структуры данных мы получаем , когда применив его, мы сделаем «настолько простым, насколько возможно» гораздо менее простым, чем «настолько простым, насколько мы хотели бы».
Эрвин Смаут,

2
Крис Дэйт, Логика и базы данных, Глава 6, «Почему логика реляционной СУБД не должна быть многозначной», стр. 145. Список ссылок на эту главу также должен быть интересным, особенно с участием Макговерана.
Эрвин Смаут,

13

Я не вижу ничего плохого в том, что это просто необязательная связь n-1, которая будет представлена ​​нулем во внешнем ключе. В противном случае, если вы поместите свою таблицу ссылок, вам придется позаботиться о том, чтобы она не стала отношениями nn, что вызвало бы еще больше проблем.


2
На самом деле это отношение 0-N, а не необязательное отношение 1-N. Но я с тобой согласен.
Эрик Дж.

5
Управление? Это простое УНИКАЛЬНОЕ ограничение на стороне 0 к 1!
wqw

2
Да, это УНИКАЛЬНОЕ ограничение, но вам также придется иметь дело с возможными исключениями позже в вашем коде из-за этого ограничения ...
pedromarce

4

В реляционной модели определенно возможны необязательные отношения.

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

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


2

Использование NULL было бы хорошим способом убрать незавершенные заказы:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Выше будут показаны заказы старше 15 минут без соответствующего идентификатора клиента.


1

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

Обычно такая ситуация возникает в веб-приложениях, где заказ детализируется до того, как клиент определит, кто он / она. И в этих ситуациях порядок сохраняется в состоянии сервера или в файле cookie до тех пор, пока не будет предоставлено все необходимое состояние для полного заказа, после чего порядок сохраняется в базе данных.

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


Заказ-заказчик был в качестве примера. В моем приложении это больше похоже на адреса. Не удалось найти сразу полностью верный пример. Спасибо.
Ливен Кардоен,

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

1

Вы всегда можете добавить искусственную строку в свою таблицу Customer, что-то вроде Id = -1 и CustomerName = 'Unknown', а затем в тех случаях, когда вы обычно устанавливаете свой CustomerId в Order NULL, установите его на -1.

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


Чтобы добавить к этому, помните, что NULLS не сохраняются в индексе (в oracle), поэтому это означает, что пропуск таблицы ссылок и переход к FK, допускающему значение NULL, имеет смысл - с точки зрения производительности. Еще одна вещь, от которой это может зависеть, - это то, хотите ли вы сохранить что-нибудь еще в этой таблице ссылок, например, КТО сделал ссылку и когда? Ссылка сейчас неактивна / удалена (а когда-то была?)
Worthy7 07

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

0

Обнуляемые FK для необязательных отношений многие-к-одному вполне подойдут.


-1

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


3
Обнуляемые столбцы могут быть от 1 до 5, но не в 6, согласно тому, что я читал.
Уолтер Митти,

-1

Да, тут что-то не так. Это не внешний ключ, если он допускает значение NULL. Дизайн своей базы данных по коду. Может вы сделаете нулевую ссылку на неназначенную. или «Не назначено», если вы используете символ col. Сохраняйте целостность ваших данных на 100%.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.