引用的表中没有索引,其中引用的列显示为第一列

lrk*_*kwz 7 mysql mariadb foreign-key ddl

我有两个现有的 mysql/mariadb 表,例如:

CREATE TABLE `ice_product` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `long_description` text DEFAULT NULL,
  `long_summary_descr` text DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `quality` varchar(255) DEFAULT NULL,
  `release_date` date DEFAULT NULL,
  `update_date` date DEFAULT NULL,
  `short_description` text DEFAULT NULL,
  `short_summary_descr` text DEFAULT NULL,
  `title` varchar(255) DEFAULT NULL,
  `category_id` bigint(20) DEFAULT NULL,
  `supplier_id` bigint(20) DEFAULT NULL,
  `updated` bit(1) NOT NULL,
  `product_family_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_ice_product_cat` (`category_id`),
  KEY `idx_ice_product_supp` (`supplier_id`),
  KEY `idx_ice_product_updated` (`updated`),
  CONSTRAINT `fk_icecat_product_cat_id` FOREIGN KEY (`category_id`) REFERENCES `ice_category` (`id`),
  CONSTRAINT `fk_icecat_product_supp_id` FOREIGN KEY (`supplier_id`) REFERENCES `ice_supplier` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
Run Code Online (Sandbox Code Playgroud)

CREATE TABLE `ice_product_manuals` (
  `product_id` bigint(20) NOT NULL,
  `descr` varchar(255) DEFAULT NULL,
  `url` varchar(800) DEFAULT NULL,
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_manual` (`product_id`,`url`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
Run Code Online (Sandbox Code Playgroud)

我想定义一个外键约束

ALTER TABLE ice_product_manuals ADD CONSTRAINT fk_icecat_manuals_product_id FOREIGN
KEY (product_id) REFERENCES ice_product(`id`);
Run Code Online (Sandbox Code Playgroud)

但该声明失败了

ERROR 1005 (HY000): Can't create table `mydb`.`ice_product_manuals` (errno: 150 "Foreign key constraint is incorrectly formed")
Run Code Online (Sandbox Code Playgroud)

SHOW ENGINE INNODB STATUS显示以下内容

------------------------
LATEST FOREIGN KEY ERROR
------------------------
2023-04-15 19:05:36 0x7f70e4065640 Error in foreign key constraint of table `mydb`.`ice_product_manuals`:
Alter  table `mydb`.`ice_product_manuals` with foreign key `fk_icecat_manuals_product_id` constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
Run Code Online (Sandbox Code Playgroud)
  • 相同的发动机
  • 相同的字符集和整理
  • 两个表都有索引
  • 两个表都是空的

哪里有问题?

https://dbfiddle.uk/psQC_4jV

ype*_*eᵀᴹ 8

您需要在 上的引用表上有一个索引ice_product_manuals (product_id)

请参阅:dbfiddle-1

由于特殊原因,您拥有的复合索引不能用于 FK 约束。通常,如果约束位于索引的第一列,则可以将两个(或更多)列索引用于 FK 约束。

然而, MariaDB有一个功能MDEV-371UNIQUE ,它为非常长的列(超过 3072 字节)实现了索引,其中指出:

允许用户创建任意长度的唯一约束。这将在上层服务器中完成,而不是在引擎中完成。服务器将创建不可见的虚拟列,该虚拟列具有对唯一列的哈希值BTREE以及该列的正常索引。在插入或更新时,它将检查索引是否存在哈希冲突,并且如果需要,将检索实际行以比较数据。”

您的复合索引确实位于非常长的(第二)列(utf8mb4 上有 800 个字符),超过 3072 个字节,因此它属于这种情况。

所以这个BTREE索引是在两列的哈希上,它不能用于FK检查。

请参阅:dbfiddle-2,如果第二列较短,则代码可以工作,并且不需要创建此 btree-on-a-hash,而是创建普通的 2 列 btree 索引。

  • 讨论[移至聊天](https://chat.stackexchange.com/rooms/145368/discussion- Between-ypercube-and-bill-karwin)。 (2认同)