Что не так с внешними ключами?


259

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

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

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


9
Я не думаю, что Джоэл не использует FK, просто он не заставляет базу данных применять их. По логике они все еще ФК!
Дарен Томас

6
Он говорит, что не использует внешние ключи, но я согласен с Дареном в том, что он имеет в виду, что он не использует внешний ключ. Столбец в одной таблице, значения которого должны быть взяты из первичного / уникального ключа другой таблицы, являются внешними ключами независимо от того, добавлено ли ограничение или нет.
Тони Эндрюс

22
... Обычно глупо не добавлять ограничение: оно ОБЕСПЕЧИВАЕТ целостность в любое время, даже если в коде приложения есть ошибка или если вы работаете за кулисами, делая «исправление» данных.
Тони Эндрюс

2
+1 За комментарий Тони. Существует слишком большая путаница между функцией и логической концепцией внешних ключей.
JohnFx

4
@ DanMan, не знаю, откуда у тебя сложилось впечатление, я так думаю. Я на самом деле говорю выше: «Вообще глупо не добавлять ограничения: это ОБЕСПЕЧИВАЕТ целостность во все времена»
Тони Эндрюс

Ответы:


352

Причины использования иностранных ключей:

  • вы не получите сиротские ряды
  • Вы можете получить хорошее поведение "при удалении каскада", автоматически очищая таблицы
  • Знание взаимосвязей между таблицами в базе данных помогает оптимизатору планировать ваши запросы для наиболее эффективного выполнения, поскольку он может получить более точные оценки количества соединений.
  • ФК дают довольно большой совет о том, какую статистику наиболее важно собирать в базе данных, что, в свою очередь, приводит к повышению производительности
  • они включают все виды автоматически сгенерированной поддержки - ORM могут генерировать себя, инструменты визуализации смогут создавать для вас удобные макеты схем и т. д.
  • кто-то новичок в проекте быстрее попадет в поток вещей, так как в противном случае неявные отношения явно задокументированы

Причины не использовать иностранные ключи:

  • вы заставляете БД работать дополнительно на каждой операции CRUD, потому что она должна проверять согласованность FK. Это может быть очень дорого, если у вас много оттока
  • усиливая отношения, FK определяют порядок, в котором вы должны добавлять / удалять вещи, что может привести к отказу БД делать то, что вы хотите. (Разумеется, в таких случаях вы пытаетесь создать «Сиротский ряд», а это обычно не очень хорошо). Это особенно болезненно, когда вы выполняете большие пакетные обновления и загружаете одну таблицу перед другой, а вторая таблица создает согласованное состояние (но следует ли вам делать такие вещи, если есть вероятность, что вторая загрузка завершится неудачно, и ваша база данных сейчас несовместима?).
  • иногда вы заранее знаете, что ваши данные будут испорчены, вы принимаете это и хотите, чтобы БД это приняла
  • ты просто ленивый :-)

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


12
Хороший список! СУБД не будут проверять согласованность для R-части CRUD, поэтому я бы убрал эту часть. Кроме того, это, вероятно, стирка, потому что в вашем приложении вы делаете то же самое, что и СУБД: вы проверяете и проверяете, что родительский идентификатор действителен до CRD, и это на самом деле медленнее, чем использование DBM!
Мэтт Рогиш

6
Что если кто-то удалит родителя, когда вы вставляете детей? Прямо сейчас, когда я отправляю «добавить комментарий» - если вы уже удалили свой ответ, этот комментарий теперь является сиротой. ФК предотвратили бы это. Кроме того, я мог бы просто изменить parentID на все, что я хочу. Кто-то должен проверить. :)
Мэтт Рогиш

7
Точно - это должна быть работа БД, так как она единственная, которая может гарантировать транзакционность в случае нескольких одновременных клиентов.
SquareCog

3
+1 Отличный ответ - можно подумать о второй причине не использовать ограничения FK, которая «усложняет нарушение согласованности», что на самом деле звучит как хорошая вещь!
Билл Карвин

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

80

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

Если, однако, вы не имели такого тщательного или позитивного опыта в прошлом, связанного с RDBMS, то, скорее всего, вы не сталкивались с такой информацией. Или, возможно, ваше прошлое включает в себя погружение в среду, которая была громогласна против базы данных (например, «эти администраторы баз данных - идиоты - мы мало, мы выбрали несколько стропальщиков кода java / c #, которые спасут день»), и в этом случае вы можете быть категорически против к мистическим болтовням некоторых двебов, говорящих вам, что ФК (и ограничения, которые они могут подразумевать) действительно важны, если вы просто послушаете.

В детстве всех учили, что чистить зубы важно. Можете ли вы обойтись без этого? Конечно, но где-то внизу у вас будет меньше доступных зубов, чем если бы вы чистили зубы после каждого приема пищи. Если бы мамы и папы были достаточно ответственны, чтобы охватить дизайн базы данных, а также гигиену полости рта, у нас не было бы этого разговора. :-)


61
Я собираюсь использовать дистиллированное «внешние ключи - это как чистить зубы: иди вперед,
обходись

5
Лично я нахожу, что принципы СУРБД гораздо проще и более четко определены, чем принципы гигиены полости рта
Али Ганджи

Я уверен, что через 10 лет я собираюсь поговорить об этом дизайне базы данных с моим сыном / дочерью, чтобы он не запутался и не стал причиной следующей аварии на Уолл-стрит из-за проблемы с базой данных.
VarunAgw

52

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

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


26
У меня действительно нет людей, у которых нет ФК в их базе данных. В прошлый раз, когда я работал с кем-то, у кого его не было, он сказал: «Нет, мы применяем это в приложении». За исключением того, что я сделал обзор всех баз данных клиентов и обнаружил, что у большинства из них были сироты ...
ErikE

1
Это, как правило, кажется, имеет место. Я думаю, что вы можете избежать принудительного применения ТОЛЬКО в базе данных (при условии, что ваши пользователи не возражают против исключений времени выполнения), но иметь оба варианта - действительно единственный путь.
AlexCuse

Все это в стенограммах / ответ Атвуда "Atwood: ... основанный на внешних ключах, которые вы установили в индексах, они выясняют это ... Spolsky: [смеется] Предполагая, что вы делаете это. Atwood: Ну, предполагая, что вы правильно настроили свою базу данных ... "
MemeDeveloper

4
Базы данных не называются реляционными из-за отношений между таблицами (КАЖДЫЙ вид базы данных имеет какие-то отношения между сущностями!), А потому, что сами таблицы являются отношениями в математических терминах. Смотрите Википедию .
Массимилиано Краус

41

Внешние ключи необходимы для любой модели реляционной базы данных.


54
Модель, да. Реализация, несущественная, просто, вероятно, полезная.
dkretz

4
Извините, но главная причина, по которой разработчики приложений не используют системы управления объектными базами данных (или базы данных NoSQL!) Более широко, заключается в инвестициях в СУБД. Большую часть времени база данных (а не система управления базой данных) представляет собой объектную модель среднего уровня, часто включающую распределенные кэши. Это где каскад удаления, владение и синхронизация изменений должны произойти в любом случае. СУБД используется в основном для сохранения этой объектной модели, и обычно после кропотливого и практически бесполезного ORM-упражнения. Модели отношений в большинстве случаев не нужны!
Сентин

2
нет, внешние ключи не обязательны для обозначения «реляционных»
Серебряная Луна,

Это мало что объясняет.
Наэ

29

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

Существует также тот факт, что несколько систем обычно должны взаимодействовать напрямую с базой данных - от других систем, которые просто считывают данные (Crystal Reports), до систем, которые вставляют данные (необязательно с использованием разработанного мной API; это может быть написано тупой менеджер, который только что обнаружил VBScript и имеет пароль SA для блока SQL). Если база данных не настолько идиотобезопасна, как может быть, пока, пока, база данных.

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


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

20

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


Внешние ключи усложняют автоматизированное тестирование

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

Тем accountsне менее, имеет внешний ключ для contracts, и contractsимеет fk to clients, и clientsимеет fk to cities, и citiesимеет fk to states.

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

На это есть как минимум две возможные перспективы:

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

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


Обычно я выбираю средний путь: я использую FK, затем пишу вспомогательные методы юнит-тестирования, которые настраивают БД для поддержки различных сценариев тестирования, например вспомогательный метод для заполнения "городов" и "штатов" для любых тестов. что нужно эти таблицы заполнены.
Joelpt

Возможно, вы должны были использовать таблицы ссылок между несвязанными объектами. Или идите дальше - отдельные DBS: рассмотрите ситуацию в сервис-ориентированной архитектуре или Microservice, где каждый элемент (клиенты, учетные записи, транзакции) представляют собой разные системы с разными DB. Нет ФК между ними, как все. В этом случае следует использовать FK для предотвращения потерянных данных в подтаблицах для каждого типа данных.
JeeBee

3
Есть также СУБД, которые позволяют ограничениям откладывать так, чтобы они проверялись только при фиксации всей транзакции, поэтому порядок вставки, обновления, удаления не имеет значения
a_horse_with_no_name

2
Если вы тестируете обновление с бизнес-уровня, в вашей среде разработки должен присутствовать FK. Когда вы обновляете свою запись, у вас должны быть значения столбцов, необходимые для успешного обновления. В противном случае, ИМХО, ваш тест недействителен.
KeyOfJ

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

16

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

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

  • ON DELETE RESTRICT- Предотвращает удаление любых строк в другой таблице, имеющих ключи в этом столбце. Это то, что Кен Рэй описал выше.
  • ON DELETE CASCADE - Если строка в другой таблице удалена, удалите все строки в этой таблице, которые ссылаются на нее.
  • ON DELETE SET DEFAULT - Если строка в другой таблице удалена, установите любые внешние ключи, ссылающиеся на нее, по умолчанию для столбца.
  • ON DELETE SET NULL - Если строка в другой таблице удалена, установите для любых внешних ключей, ссылающихся на нее в этой таблице, значение null.
  • ON DELETE NO ACTION- Этот внешний ключ только означает, что он является внешним ключом; а именно для использования в мапперах.

Эти же действия относятся и к ON UPDATE.

По умолчанию, кажется, зависит от того, какой сервер вы используете.


14

@imphasing - это именно тот тип мышления, который вызывает кошмары обслуживания.

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


Поскольку вовлеченные разработчики никогда не решали проблему, которая требует нетривиальной, нормализованной, реляционной модели. Многие проблемы этого не делают, особенно те, которые имеются в программировании типа веб / "социальные медиа", которое сегодня является повальным увлечением. Если что-либо, находящееся в бэк-энде платформы ORM, удовлетворит проблему в альфа-версии, вряд ли кто-то задумается о моделировании данных. Многие такие проблемы легко решаются с помощью K / V хранилищ, баз данных документов или прямой сериализации объектов.
zxq9

12

Есть одна веская причина не использовать их: если вы не понимаете их роль или то, как их использовать.

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

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


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

2
@Guillaume Я думаю, что его ответ был немного саркастичным, его нельзя воспринимать буквально: если вы не понимаете их, то не используйте их. Но, конечно, вы должны понимать и использовать их.
Бенджамин

^ Это. Они полезные инструменты, но в руках новичка, они опасные инструменты.
Кент Фредрик

11

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


11
Почему осиротевшие строки имеют большое значение?
Сеун Осева

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

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

4

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

На протяжении жизненного цикла приложения проверка ссылок и данных ограничивает сбор данных полиции через приложение, особенно когда новые требования приводят к изменениям логического приложения.

Что касается предмета этого списка - внешний ключ сам по себе не «повышает производительность» и не «значительно снижает производительность» с точки зрения системы обработки транзакций в реальном времени. Однако в «пакетной» системе ВЫСОКОГО объема используется совокупная стоимость проверки ограничений. Итак, вот разница между процессом в реальном времени и процессом пакетной обработки; пакетная обработка - когда совокупные затраты, связанные с проверками ограничений, для последовательно обработанной партии представляют собой снижение производительности.

В хорошо спроектированной системе проверки непротиворечивости данных будут выполняться «до» обработки пакета (тем не менее, здесь также есть стоимость); поэтому проверки ограничений внешнего ключа не требуются во время загрузки. Фактически все ограничения, включая внешний ключ, должны быть временно отключены до обработки пакета.

QUERY PERFORMANCE - если таблицы объединяются по внешним ключам, следует учитывать тот факт, что столбцы внешнего ключа НЕ УКАЗАНЫ (хотя соответствующий первичный ключ индексируется по определению). Индексирование внешнего ключа, в этом отношении, индексация любого ключа и присоединение таблиц к индексированным помогает повысить производительность, а не присоединение к неиндексированному ключу с ограничением внешнего ключа.

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


Ну, я не знаю, почему вставка 3-х двойных символов новой строки вместо пробелов и изменение двух слов считается «67% - это Джонатан Леффлер», но я не думаю, что я проделал такую ​​большую работу над этим. Основной текст предоставлен @jay (пользователь 183837).
Джонатан Леффлер

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

3

Дополнительная причина для использования внешних ключей: - Позволяет большее повторное использование базы данных

Дополнительная причина НЕ использовать иностранные ключи: - Вы пытаетесь заблокировать клиента в своем инструменте, уменьшая повторное использование.


3

Исходя из моего опыта, всегда лучше избегать использования FKs в критических приложениях базы данных. Я бы не стал спорить с парнями, которые говорят, что FK - это хорошая практика, но она не практична, когда база данных огромна и имеет огромные операции CRUD / сек. Я могу поделиться без имен ... один из крупнейших инвестиционных банков не имеет ни одного ФК в базах данных. Эти ограничения обрабатываются программистами при создании приложений с использованием БД. Основная причина в том, что когда делается новый CRUD, он должен воздействовать на несколько таблиц и проверять каждую вставку / обновление, хотя это не будет большой проблемой для запросов, затрагивающих отдельные строки, но создает огромную задержку при работе с пакетная обработка, которую любой крупный банк должен выполнять как повседневные задачи.

Лучше избегать ФК, но его риск должен быть решен программистами.


8
Я не думаю, что практика развития в крупных банках устанавливает золотой стандарт.
Адриан Костер

3

«Перед добавлением записи убедитесь, что соответствующая запись существует в другой таблице» - это бизнес-логика.

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

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

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

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

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


2

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

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


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

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

2

База данных Clarify является примером коммерческой базы данных, которая не имеет первичных или внешних ключей.

http://www.geekinterview.com/question_details/18869

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

Другими словами, они могли бы присоединиться к таблицам с явными объявлениями (DRI), но решили не делать этого .

Следовательно, база данных Clarify полна несоответствий и неэффективна.

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

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


Код для обработки неудачной проверки ссылочной целостности намного меньше кода для обработки противоречивых данных.
Джей Годсе

@ Джей согласен! Не думаю, что я защищаю этот подход.
Эд Гинесс

2

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

Значение: осиротевшие строки? Нет. Никогда не видел этого в моей жизни. Если только плохой программист не забыл внешний ключ или не реализовал его на другом уровне. И то, и другое - в контексте Oracle - огромные ошибки, которые приведут к дублированию данных, потерям данных и, следовательно, к повреждению данных. Я не могу представить базу данных без применения ФК. Это похоже на хаос для меня. Это немного похоже на систему разрешений Unix: представьте, что все - root. Подумай о хаосе.

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

Недостатки? Да, конечно ! Потому что при вставке будет происходить намного больше проверок. Но, если целостность данных важнее производительности, это не сложно. Проблема с производительностью в Oracle больше связана с индексами, которые поставляются с PK и FK.


1

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

Если вы выбрали свой первичный ключ неразумно, то изменение этого значения становится еще более сложным. Например, если у меня в качестве имени человека указан PK моей таблицы «customer», и я сделаю этот ключ FK в таблице «orders», если клиент хочет изменить свое имя, то это королевская боль ... но это просто плохой дизайн базы данных.

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


5
Я, как правило, редко удаляю вещи. Просто отметьте «Видимый / активный» бит.
Дана

+1 за «Я считаю, что преимущества использования огненных ключей перевешивают любые предполагаемые недостатки»
Ян Бойд

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

Изменение имени клиента не будет проблемой, если ваш внешний ключ установлен в CustomerId (PK). в таблице заказов. Единственный способ причинить боль - это установить FK на CustomerName, чего никогда не должно быть. ИМХО
KeyOfJ

1

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


6
Сколько процессорного времени тратится на удаление дублирующих и противоречивых данных?
Эд Гиннес

Да, это правда. В системе, над которой я работаю, мы должны вставлять 10-40 гигабайт данных за раз в базу данных, и производительность FK с и без видима в общем времени, которое требуется.
Пол Мендоса

1

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


9
Я полагаю, что реальная причина, по которой ограничения FK не используются некоторыми (большинство, с моей точки зрения), является чистой ленью под предлогом, что они могут защитить свою лень с помощью своего аргумента об экономии производительности. Я твердо верю, что подавляющее большинство расходов на глупость, которые несет наша компания, связано с недостаточным соблюдением ограничений FK и волнового эффекта, который это оказывает через компанию. Нехватка уникальных ключей - это еще одна вещь, которая сводит меня с ума после 2000+ строк хранимых процедур с 12 уровнями вложенных IF и случайным отступом, но я остановлюсь сейчас.
Чад

1

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

РЕДАКТИРОВАТЬ: я думаю, что он имел в виду ограничения внешнего ключа , а не внешние ключи в качестве концепции.


Нет. Ему не нравятся настоящие ключи!
LJS

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

Да, я был шокирован, когда услышал его. Однако он мог быть непреднамеренно насмешливым; возможно, он опубликует здесь и уточнить на каком-то этапе :-)
ljs

1

Для меня, если вы хотите следовать стандартам ACID , очень важно иметь внешние ключи для обеспечения ссылочной целостности.


1

Я должен повторить большинство комментариев здесь. Внешние ключи являются необходимыми элементами для обеспечения целостности ваших данных. Различные опции для ON DELETE и ON UPDATE позволят вам обойти некоторые «падения», которые люди упоминают здесь относительно их использования.

Я обнаружил, что в 99% всех моих проектов у меня есть FK для обеспечения целостности данных, однако есть те редкие случаи, когда у меня есть клиенты, которые ДОЛЖНЫ хранить свои старые данные, независимо от того, насколько они плохие .... но потом я трачу много времени на написание кода, который в любом случае получает только действительные данные, так что это становится бессмысленным.


1

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


1

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

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

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

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

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


1

Я повторяю ответ Дмитрия - очень хорошо сказано.

Для тех, кого беспокоит нехватка производительности, которую часто приносят FK, есть способ (в Oracle) получить преимущество оптимизатора запросов от ограничения FK без дополнительных затрат на проверку ограничения во время вставки, удаления или обновления. То есть создать ограничение FK с атрибутами RELY DISABLE NOVALIDATE. Это означает, что оптимизатор запросов ПРИНИМАЕТ, что ограничение было применено при построении запросов, при этом база данных фактически не применяла ограничение Вы должны быть очень осторожны, чтобы взять на себя ответственность, когда вы заполняете таблицу с помощью ограничения FK, как это, чтобы быть абсолютно уверенным, что у вас нет данных в ваших столбцах FK, которые нарушают ограничение, как если бы вы это сделали мог получить ненадежные результаты из запросов, включающих таблицу, к которой относится это ограничение FK.

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


1

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

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

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


5
«Приложения никогда не должны обновлять базу данных напрямую и должны быть с помощью хранимой процедуры. Это сохраняет базу кода внутри базы данных и означает, что база данных сохраняет свою целостность». <- Здесь есть предположение, что логика в хранимых процедурах не может нарушать целостность данных, что просто неправильно.
Тим Готье

1

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

Но вот еще одна очень хорошая причина из реальной жизни вообще не использовать внешние ключи:

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

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

Это может привести к различным проблемам:

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

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

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

Никто не знает, как ведут себя все эти системы БД, но ваша бизнес-логика с проверками целостности всегда остается неизменной.


0

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


Это было скорее неординарное замечание, чем дискуссия, хотя, возможно, мне следует выяснить, что он думает по этому вопросу независимо! Однако мне было интересно узнать мнение сообщества по этой теме!
LJS

0

Однажды, когда FK может вызвать у вас проблему, это когда у вас есть исторические данные, которые ссылаются на ключ (в таблице поиска), даже если вы больше не хотите, чтобы ключ был доступен.
Очевидно, что решение состоит в том, чтобы лучше спроектировать вещи заранее, но я думаю о реальных ситуациях, когда вы не всегда можете полностью контролировать решение.
Например: возможно, у вас есть справочная таблица, в customer_typeкоторой перечислены различные типы клиентов - допустим, вам нужно удалить определенный тип клиентов, но (из-за ограничений бизнеса) не удается обновить программное обеспечение клиента, и никто не обращал внимания на эту ситуацию При разработке программного обеспечения тот факт, что он является внешним ключом в какой-то другой таблице, может помешать вам удалить строку, даже если вы знаете исторические данные, которые ссылаются на нее, не имеет значения.
После нескольких сожжений вы, вероятно, откажетесь от навязывания отношений с БД.
(Я не говорю, что это хорошо, просто приводя причину, по которой вы можете решить избегать FKs и db-ограничений вообще)


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