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


15

Скажем, у меня есть следующая диаграмма ER:

введите описание изображения здесь

Теперь, если бы я представлял отношение с помощью внешнего ключа Schoolin Student, у меня могли бы быть NULLзначения (потому что a Student не обязательно должен принадлежать a School), например:

введите описание изображения здесь

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

введите описание изображения здесь

Таким образом, никакие NULLзначения не могут присутствовать в таблице School_has_Student.

Но каковы недостатки использования обнуляемого внешнего ключа вместо создания таблицы пересечений?


Редактировать:

Я по ошибке выбрал ( school_id, student_id) в качестве первичного ключа для School_has_Studentтаблицы, что сделало отношения многие ко многим. Правильный первичный ключ должен был быть student_id:

введите описание изображения здесь


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

1
Я согласен с Доком по поводу ложной предпосылки, но, может быть, все еще достаточно ясно, чтобы ответить?
MetaFight

Есть ложная предпосылка, но ее достаточно легко исправить и объяснить разницу.

Я отказался от своего близкого голоса, но предложение «Итак, правильный путь (основываясь на том, что я прочитал) - создать таблицу пересечений для представления отношений», создает впечатление, что вы должны сказать нам, какой источник сказал вам, что это » правильный путь. В каждом учебнике, который я читал ранее, канонический способ отношений 1: n - это один внешний ключ. Или вы что-то не так поняли?
Док Браун

@ Док Браун Я не помню, где я это прочитал, но я уверен, что там написано, что таблица пересечений была правильной. В любом случае, можете ли вы дать мне название книги, в которой говорится, что отношение 1: n (с необязательным участием на стороне: 1) должно быть представлено с использованием одного внешнего ключа, мне интересно прочитать, что они говорят по этому вопросу.
Том

Ответы:


18

Две модели представляют разные отношения.

Используя таблицу соединений, вы моделируете отношение «многие ко многим».

Используя простой внешний ключ, вы моделируете отношение «один ко многим».

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


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

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

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

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


Поэтому, если я моделирую отношение «один ко многим» (с необязательным участием на стороне: 1), мне следует использовать внешний ключ, несмотря на то, что он может иметь NULLзначения?
Том

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

1
Я отредактировал на мой вопрос. Я только сделал student_idпервичный ключ в School_has_Studentтаблице, который сохранил отношения как один ко многим. Какие недостатки у этого метода по сравнению с использованием внешнего ключа?
Том

@ Том я отредактировал свой ответ.

6

Вы написали в комментарии выше:

в книге «Основы систем баз данных» [...] говорится, что рекомендуется использовать таблицу пересечений, если в столбце внешнего ключа много значений NULL (например, если 98% сотрудников не заведуй отделом)

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

В противоположность этому, если у вас не просто несколько значений NULL, скажем, 50% или более отношений не являются NULL, использование таблицы пересечений дает противоположный эффект - больше дискового пространства, более высокая сложность, приводящая к увеличению сетевого трафика и т. Д.

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

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

Так что не поймите эту рекомендацию неправильно. Книга не говорит вам, чтобы вы предпочитали таблицы пересечений для {0,1}:nотношений в целом или - как вы писали - что это «правильный путь». Используйте такие оптимизации, которые сделают ваши программы более сложными только тогда, когда они вам действительно нужны.


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

@gardenhead: что заставляет вас верить, что это "более чем вероятно"?
Док Браун

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

@gardenhead: звучит для меня, что вы делаете гораздо больше необоснованных предположений, чем я. Тем не менее, см. Мое редактирование.
Док Браун

2

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

введите описание изображения здесь

Физическая модель будет выглядеть так, что , тем не менее, сбивает с толку (люди будут думать, что это M: M, если они не увидят внимательно):

введите описание изображения здесь

Мое предложение:

Если у вас есть несколько столбцов (FK или иным образом), которые не относятся к большинству учащихся, разделите таблицы на таблицы ролей с соотношением 1: 1. Но это не потому, что они FK, а потому, что столбцы не применяются к большинству строк.

В противном случае , обнуляемый FK является нормальной частью базы данных и объединения таблиц, как правило , для M: M RELS.

Обычно используются значения 1: 1 для таблиц ролей, имеющих столбцы, которые применяются только в том случае, если объект имеет определенный тип, и извлекающих BLOB-столбцы с целью повышения производительности или хранения. Аводирование нулевых значений в FK не является одним из распространенных случаев для этого.

введите описание изображения здесь


2

В дополнение к другим ответам я хотел бы отметить, что нулевое значение для внешнего ключа неоднозначно. Значит ли это:

1) Школа учащегося (если есть) неизвестна (это стандартное значение «ноль» - значение неизвестно)

2) Известно, есть ли у ученика школа, и нет

Если вы используете стандартное значение «ноль», как бы вы представляли «ученик не имеет школы» в своей модели внешнего ключа. В этом случае вам, вероятно, придется создать запись «no school» с собственным идентификатором в школьной таблице. (Не идеально)


2
В книге «Основы систем баз данных» упоминается, что существует 3 интерпретации NULL, это может означать: 1) Неизвестное значение. 2) Недоступно или удержано значение. 3) Неприменимый атрибут (я думаю, что эта интерпретация означает, что вы можете указать NULLдля внешнего ключа).
Том

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

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

@ Том Да, я считаю, что лучше в этом случае
Брэд Томас

@BradThomas - чтобы избежать той же двусмысленности при использовании таблицы пересечений, вы бы представили случай 2 (известно, что у ученика нет школы) записью в таблице пересечений с NULL School_ID?
Андрей

1

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

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

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

В базах данных: оптимизировать под вопросы, которые вы задаете.


0

Существует случай, когда использование третьей таблицы может иметь смысл. Пример может показаться чисто гипотетическим, но я надеюсь, что он хорошо иллюстрирует мою точку зрения. Предположим, что вы добавили в studentsтаблицу больше столбцов, и в какой-то момент вы решили применить уникальность записей с помощью составного индекса для нескольких столбцов. Вполне вероятно, что вам также придется включить school_idколонку, и здесь все становится грязным. Благодаря тому, как был спроектирован SQL, будет возможно вставить несколько одинаковых записей, где school_idэто NULLвозможно. Это имеет смысл с технической точки зрения, но противоречит здравому смыслу и может привести к неожиданным результатам. С другой стороны, обеспечить уникальность таблицы пересечения легко.

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

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


0

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

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

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