Что не так с внешними ключами? - PullRequest
245 голосов
/ 17 сентября 2008

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

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

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

Ответы [ 37 ]

339 голосов
/ 17 сентября 2008

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

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

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

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

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

78 голосов
/ 17 сентября 2008

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

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

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

52 голосов
/ 17 сентября 2008

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

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

39 голосов
/ 17 сентября 2008

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

29 голосов
/ 17 сентября 2008

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

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

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

18 голосов
/ 26 октября 2012

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


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

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

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

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

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

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

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

14 голосов
/ 17 сентября 2008

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

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

14 голосов
/ 17 сентября 2008

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

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

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

Эти же действия применимы и к ON UPDATE.

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

12 голосов
/ 17 сентября 2008

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

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

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

11 голосов
/ 17 сентября 2008

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

...