1.7.2.3 Отличия ограничений FOREIGN KEY
Реализация ограничений внешнего ключа в MySQL отличается от стандарта SQL по следующим ключевым аспектам:
-
Если в родительской таблице есть несколько строк с одинаковым значением ключевого поля ссылки,
InnoDBвыполняет проверку внешнего ключа так, как если бы других строк родительской таблицы с одинаковым значением ключа не существовало. Например, если вы определяете ограничение типаRESTRICT, и есть строка дочерней таблицы со множеством строк родительской таблицы,InnoDBне допускает удаление ни одной из строк родительской таблицы. Это показано в следующем примере:mysql>
CREATE TABLE parent (->id INT,->INDEX (id)->) ENGINE=InnoDB;Query OK, 0 rows affected (0.04 sec) mysql>CREATE TABLE child (->id INT,->parent_id INT,->INDEX par_ind (parent_id),->FOREIGN KEY (parent_id)->REFERENCES parent(id)->ON DELETE RESTRICT->) ENGINE=InnoDB;Query OK, 0 rows affected (0.02 sec) mysql>INSERT INTO parent (id)->VALUES ROW(1), ROW(2), ROW(3), ROW(1);Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql>INSERT INTO child (id,parent_id)->VALUES ROW(1,1), ROW(2,2), ROW(3,3);Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql>DELETE FROM parent WHERE id=1;ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE RESTRICT) Если
ON UPDATE CASCADEилиON UPDATE SET NULLрекурсивно обновляют одну и ту же таблицу, которую они ранее обновили в рамках одной каскадной операции, то они ведут себя какRESTRICT. Это означает, что вы не можете использовать самоссылочныеON UPDATE CASCADEилиON UPDATE SET NULLоперации. Это предотвращает бесконечные циклы, возникающие из-за каскадных обновлений. СамоссылочныеON DELETE SET NULL, в свою очередь, возможны, как и самоссылочныеON DELETE CASCADE. Каскадные операции не могут быть вложены глубже 15 уровней.В операторе SQL, который вставляет, удаляет или обновляет множество строк, ограничения внешних ключей (как и ограничения уникальности) проверяются по строкам. При выполнении проверок внешних ключей
InnoDBустанавливает общие блокировки на уровне строк для дочерних или родительских записей, которые необходимо проверить. MySQL проверяет ограничения внешних ключей немедленно; проверка не откладывается до подтверждения транзакции. Согласно стандарту SQL, поведение по умолчанию должно быть отложенной проверкой. То есть, ограничения проверяются только после обработки всего оператора SQL. Это означает, что невозможно удалить строку, которая ссылается на себя с помощью внешнего ключа.-
Ни один из двигателей хранилища, включая
InnoDB, не распознает или не выполняет ограничениеMATCH, используемое в определениях ограничений целостности ссылок. Использование явногоMATCHпредложения не имеет указанного эффекта и приводит к тому, что предложенияON DELETEиON UPDATEигнорируются. Следует избегать указанияMATCH.Предложение
MATCHв стандарте SQL управляет тем, как обрабатываются значенияNULLв составном (многоколонном) внешнем ключе при сравнении с первичным ключом в таблице ссылок. MySQL по существу реализует семантику, определённуюMATCH SIMPLE, что позволяет внешнему ключу быть полностью или частичноNULL. В этом случае строка (дочерней таблицы), содержащая такой внешний ключ, может быть вставлена, даже если она не соответствует никакой строке в таблице ссылок (родительской). (Можно реализовать другую семантику, используя триггеры.) -
Ограничение
FOREIGN KEY, ссылающееся на не-UNIQUEключ, не является стандартным SQL, а является расширениемInnoDB, которое сейчас устарело и должно быть включено, установивrestrict_fk_on_non_standard_key. Следует ожидать, что поддержка использования нестандартных ключей будет удалена в будущих версиях MySQL, и перейти к их использованию сейчас.Двигатель хранилища
NDBтребует явного уникального ключа (или первичного ключа) на любом поле, указанном как внешний ключ, в соответствии со стандартом SQL. Для двигателей хранилища, которые не поддерживают внешние ключи (например,
MyISAM), MySQL Server анализирует и игнорирует спецификации внешних ключей.-
MySQL анализирует, но игнорирует “встроенные
REFERENCESспецификации” (как определено в стандарте SQL), где ссылки определены как часть спецификации столбца. MySQL принимаетREFERENCESпредложения только в случае указания в отдельнойFOREIGN KEYспецификации.Определение столбца с использованием
REFERENCESпредложения не имеет реального эффекта и служит только как напоминание или комментарий о том, что столбец, который вы в данный момент определяете, предназначен для ссылки на столбец в другой таблице. Важно понимать при использовании этого синтаксиса, что:tbl_name(col_name)MySQL не выполняет никаких проверок, чтобы убедиться, что
col_nameдействительно существует вtbl_name(или даже то, чтоtbl_nameсамо по себе существует).MySQL не выполняет никаких действий над
tbl_name, таких как удаление строк в ответ на действия, выполняемые над строками в таблице, которую вы определяете; другими словами, этот синтаксис не вызываетON DELETEилиON UPDATEповедения. (Хотя вы можете написатьON DELETEилиON UPDATEпредложения как частьREFERENCESпредложения, они также игнорируются).Этот синтаксис создаёт столбец; он не создаёт каких-либо индексов или ключей.
Созданный таким образом столбец можно использовать как столбец для объединения, как показано здесь:
CREATE TABLE person ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, name CHAR(60) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE shirt ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, style ENUM('t-shirt', 'polo', 'dress') NOT NULL, color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL, owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id), PRIMARY KEY (id) ); INSERT INTO person VALUES (NULL, 'Antonio Paz'); SELECT @last := LAST_INSERT_ID(); INSERT INTO shirt VALUES ROW(NULL, 'polo', 'blue', @last), ROW(NULL, 'dress', 'white', @last), ROW(NULL, 't-shirt', 'blue', @last); INSERT INTO person VALUES (NULL, 'Lilliana Angelovska'); SELECT @last := LAST_INSERT_ID(); INSERT INTO shirt VALUES ROW(NULL, 'dress', 'orange', @last), ROW(NULL, 'polo', 'red', @last), ROW(NULL, 'dress', 'blue', @last), ROW(NULL, 't-shirt', 'white', @last); SELECT * FROM person; +----+---------------------+ | id | name | +----+---------------------+ | 1 | Antonio Paz | | 2 | Lilliana Angelovska | +----+---------------------+ SELECT * FROM shirt; +----+---------+--------+-------+ | id | style | color | owner | +----+---------+--------+-------+ | 1 | polo | blue | 1 | | 2 | dress | white | 1 | | 3 | t-shirt | blue | 1 | | 4 | dress | orange | 2 | | 5 | polo | red | 2 | | 6 | dress | blue | 2 | | 7 | t-shirt | white | 2 | +----+---------+--------+-------+ SELECT s.* FROM person p INNER JOIN shirt s ON s.owner = p.id WHERE p.name LIKE 'Lilliana%' AND s.color <> 'white'; +----+-------+--------+-------+ | id | style | color | owner | +----+-------+--------+-------+ | 4 | dress | orange | 2 | | 5 | polo | red | 2 | | 6 | dress | blue | 2 | +----+-------+--------+-------+Когда используется в таком формате, предложение
REFERENCESне отображается в выводеSHOW CREATE TABLEилиDESCRIBE:mysql>
SHOW CREATE TABLE shirt\G*************************** 1. row *************************** Table: shirt Create Table: CREATE TABLE `shirt` ( `id` smallint(5) unsigned NOT NULL auto_increment, `style` enum('t-shirt','polo','dress') NOT NULL, `color` enum('red','blue','orange','white','black') NOT NULL, `owner` smallint(5) unsigned NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Сведения об ограничениях внешних ключей см. в разделе 15.1.20.5, «Ограничения FOREIGN KEY».
© 2025 Oracle
Licensed under the GPLv2 License.