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

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

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

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

Ответы [ 37 ]

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

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

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

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

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

1 голос
/ 26 марта 2013

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

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

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

1 голос
/ 14 сентября 2015

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

0 голосов
/ 15 апреля 2015

Q очень часто мы получаем ошибки с ограничениями FK Невозможно добавить или обновить дочернюю строку: ограничение внешнего ключа не выполнено Предположим, что есть две таблицы inventory_source и contract_lines, и мы ссылаемся на inventory_source_id в contract_lines из inventory_source и предположим, что мы хотим удалить запись из inventory_source и запись уже присутствует в contract_lines или мы хотим удалить столбец PK Базовая таблица, мы получаем ошибки для ограничений FK, мы можем избежать этого, используя шаги, указанные ниже.

CREATE TABLE inventory_source (
inventory_source_id int(11) NOT NULL AUTO_INCREMENT,
display_name varchar(40) NOT NULL,
state_id int(11) NOT NULL,
PRIMARY KEY (inventory_source_id),
KEY state_id (state_id),
CONSTRAINT ba_inventory_source_state_fk FOREIGN KEY (state_id) REFERENCES   ba_state (state_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE contract_lines(
contract_line_id int(11) NOT NULL AUTO_INCREMENT,
inventory_source_id int(11) NULL ,
PRIMARY KEY (contract_line_id),
UNIQUE KEY contract_line_id (contract_line_id),
KEY AI_contract_line_id (contract_line_id),
KEY contract_lines_inventory_source_fk (inventory_source_id),
CONSTRAINT contract_lines_inventory_source_fk FOREIGN KEY       (inventory_source_id) REFERENCES ba_inventory_source (inventory_source_id)
) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8 ;

Мы можем преодолеть это, используя следующие шаги: -

  1. Удаление или обновление строки из inventory_source автоматически удаляет или обновляет совпадающие строки в таблице contract_lines, что называется каскадным удалением или обновлением.
  2. Еще один способ сделать это - установить для столбца i.e inventory_source_id в таблице contract_lines значение NULL, когда соответствующая ему запись удаляется в таблице inventory_source.
  3. Мы можем ограничить родительскую таблицу для удаления или обновления, другими словами, можно отклонить операцию удаления или обновления для таблицы inventory_source.
  4. Попытка удалить или обновить значение первичного ключа не будет разрешена, если в ссылочной таблице есть соответствующее значение внешнего ключа.
0 голосов
/ 17 сентября 2008

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

...