1.7.2.3 外鍵約束差異

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 CASCADEON UPDATE SET NULL 遞迴以更新先前在相同階層期間已更新的相同表格,則其行為類似 RESTRICT。這表示您不能使用自我參考的 ON UPDATE CASCADEON UPDATE SET NULL 作業。這是為了防止級聯更新導致無限迴圈。另一方面,自我參考的 ON DELETE SET NULL 是可能的,自我參考的 ON DELETE CASCADE 也是如此。階層操作的巢狀層級不得超過 15 層。

  • 在插入、刪除或更新多個資料列的 SQL 陳述式中,會逐列檢查外鍵約束(如唯一約束)。在執行外鍵檢查時,InnoDB 會在它必須檢查的子或父記錄上設定共用的資料列層級鎖定。MySQL 會立即檢查外鍵約束;檢查不會延遲到交易提交。根據 SQL 標準,預設行為應該是延遲檢查。也就是說,只有在處理完整個 SQL 陳述式後才會檢查約束。這表示無法使用外鍵刪除參考自身的資料列。

  • 沒有任何儲存引擎(包括 InnoDB)會辨識或強制執行參考完整性約束定義中使用的 MATCH 子句。使用明確的 MATCH 子句不會產生指定的效果,並且會導致忽略 ON DELETEON UPDATE 子句。應避免指定 MATCH

    SQL 標準中的 MATCH 子句會控制在與參考表格中的主鍵比較時,如何處理複合式(多欄)外鍵中的 NULL 值。MySQL 基本上會實作 MATCH SIMPLE 定義的語意,該語意允許外鍵全部或部分為 NULL。在這種情況下,即使它與參考的(父)表格中的任何資料列都不符,仍然可以插入包含此外鍵的(子表格)資料列。(可以使用觸發程序實作其他語意。)

  • 參考非 UNIQUE 鍵的 FOREIGN KEY 約束不是標準 SQL,而是 InnoDB 擴充功能,現在已棄用,且必須透過設定 restrict_fk_on_non_standard_key 來啟用。您應該預期未來版本的 MySQL 將移除對使用非標準金鑰的支援,並立即遷移離開它們。

    根據 SQL 標準,NDB 儲存引擎需要在任何參考為外鍵的欄位上,使用明確的唯一索引鍵(或主鍵)。

  • 對於不支援外鍵的儲存引擎(例如 MyISAM),MySQL 伺服器會剖析並忽略外鍵規格。

  • 先前版本的 MySQL 會剖析但忽略內嵌 REFERENCES 規格(如 SQL 標準中定義),其中參考定義為欄位規格的一部分。MySQL 9.0 接受此類 REFERENCES 子句,並強制執行由此建立的外鍵。此外,MySQL 9.0 允許隱式使用父表格的主鍵。這表示下列語法有效

    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('tee', 'polo', 'dress') NOT NULL,
        color ENUM('red', 'blue', 'yellow', 'white', 'black') NOT NULL,
        owner SMALLINT UNSIGNED NOT NULL REFERENCES person,
        PRIMARY KEY (id)
    );

    您可以透過檢查 SHOW CREATE TABLEDESCRIBE 的輸出,來了解這是否有效,如下所示

    mysql> SHOW CREATE TABLE shirt\G
    *************************** 1. row ***************************
           Table: shirt
    Create Table: CREATE TABLE `shirt` (
      `id` smallint unsigned NOT NULL AUTO_INCREMENT,
      `style` enum('tee','polo','dress') NOT NULL,
      `color` enum('red','blue','yellow','white','black') NOT NULL,
      `owner` smallint unsigned NOT NULL,
      PRIMARY KEY (`id`),
      KEY `owner` (`owner`),
      CONSTRAINT `shirt_ibfk_1` FOREIGN KEY (`owner`) REFERENCES `person` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

如需外鍵約束的詳細資訊,請參閱 第 15.1.20.5 節,「外鍵約束」