簡體   English   中英

為什么 MySQL 沒有正確命名我的外鍵?

[英]Why is MySQL not properly naming my foreign key?

請考慮我在 MySQL 8.0.22(在 InnoDB 數據庫中)中運行的以下 SQL 代碼:

CREATE TABLE `person` (
  `person_id` smallint unsigned NOT NULL AUTO_INCREMENT, 
  `name` varchar(128) NOT NULL,
  PRIMARY KEY (`person_id`)
);

CREATE TABLE `pet` (
  `pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  PRIMARY KEY (`pet_id`)
);

ALTER TABLE `pet`
  ADD COLUMN `owner_id` smallint unsigned;

ALTER TABLE `pet`
  ADD CONSTRAINT `fk_pet_person`
  FOREIGN KEY `idx_fk_pet_person` (`owner_id`)
  REFERENCES `person` (`person_id`);

SHOW CREATE TABLE pet;

SHOW CREATE TABLE pet的 output 是:

CREATE TABLE `pet` (
  `pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `owner_id` smallint unsigned DEFAULT NULL,
  PRIMARY KEY (`pet_id`),
  KEY `fk_pet_person` (`owner_id`),
  CONSTRAINT `fk_pet_person` FOREIGN KEY (`owner_id`) REFERENCES `person` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

在上面的idx_fk_pet_person中,我在ALTER TABLE命令中將其名稱指定為 idx_fk_pet_person 時,為什么 KEY 名為fk_pet_person 我怎樣才能讓它如此命名?

您混淆了 FOREIGN KEY 和使其工作的 INDEX。 請注意 - 代碼中顯示的約束定義中沒有表達式名稱(看起來像索引定義但不是)。

當沒有合適的索引讓約束起作用時,則自動創建該索引,並將約束名稱用作索引名稱。 如果存在合適的索引,則不會發生自動創建。

如果您希望索引具有定義的名稱,則必須在創建約束之前在單獨的ALTER TABLE (子) 語句中創建此索引:

ALTER TABLE `pet`
  ADD KEY `idx_fk_pet_person` (`owner_id`),
  ADD CONSTRAINT `fk_pet_person`
  FOREIGN KEY (`owner_id`)
  REFERENCES `person` (`person_id`);

或者

ALTER TABLE `pet`
  ADD KEY `idx_fk_pet_person` (`owner_id`);

ALTER TABLE `pet`
  ADD CONSTRAINT `fk_pet_person`
  FOREIGN KEY (`owner_id`)
  REFERENCES `person` (`person_id`);

演示

MySQL 文檔指定了創建外鍵的語法:

[CONSTRAINT [symbol]] FOREIGN KEY
    [index_name] (col_name, ...)
    REFERENCES tbl_name (col_name,...)
    [ON DELETE reference_option]
    [ON UPDATE reference_option]

reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT

我的代碼沒有設置[index_name]的原因有兩個,而是索引名稱自動與約束名稱相同。 從 MySQL 8.0 參考手冊第13.1.20.5 節外鍵約束的這段中可以看出兩者:

在 MySQL 8.0.16 之前,如果未定義 CONSTRAINT 符號子句,或者未在 CONSTRAINT 關鍵字之后包含符號,則 InnoDB 和 NDB 存儲引擎都將使用 FOREIGN_KEY index_name(如果已定義)。 在 MySQL 8.0.16 及更高版本中,忽略 FOREIGN_KEY index_name。

第一個原因是我在 MySQL 8.0.22 中運行代碼。

第二個原因是我應該省略約束名稱。

@akina 的答案中的解決方法確實使我能夠為與約束名稱不同的外鍵(索引)指定一個名稱。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM