首页 > 解决方案 > InnoDB - 双向多对多外键检查

问题描述

我正在尝试在表中建立多对多关系: a keywordcan 与 another 相关keyword,并且当添加该关系时,还必须建立另一个方向。

上运行10.5.9-MariaDB

CREATE TABLE `related_keywords` (
  `relation_id` int(12) NOT NULL AUTO_INCREMENT COMMENT 'Laravel/Eloquent pk crutch',
  `keyword_1` bigint(20) unsigned NOT NULL,
  `keyword_2` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`relation_id`),
  UNIQUE KEY `rel_kw_left_to_right` (`keyword_1`,`keyword_2`),
  UNIQUE KEY `rel_kw_right_to_left` (`keyword_2`,`keyword_1`),
  CONSTRAINT `fk_rel_kw_1_exists` FOREIGN KEY (`keyword_1`) REFERENCES `keywords` (`keyword_id`) ON DELETE CASCADE,
  CONSTRAINT `fk_rel_kw_2_exists` FOREIGN KEY (`keyword_2`) REFERENCES `keywords` (`keyword_id`) ON DELETE CASCADE,
  CONSTRAINT `fk_related_kw_lr` FOREIGN KEY (`keyword_1`, `keyword_2`) REFERENCES `related_keywords` (`keyword_2`, `keyword_1`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `ck_rel_kw_differ` CHECK (`keyword_1` <> `keyword_2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

为了添加一个,还必须添加另一个。同样,删除一行必须删除另一行。但是,由于外键检查强制执行此操作,我无法在不添加第二个的情况下添加第一个:

INSERT INTO related_keywords (keyword_1, keyword_2) VALUES
    (119250770368532480, 119251038153871360),
    (119251038153871360, 119250770368532480);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`keyword_db`.`related_keywords`, CONSTRAINT `fk_related_keyword_lr` FOREIGN KEY (`keyword_1`, `keyword_2`) REFERENCES `related_keywords` (`keyword_2`, `keyword_1`) ON DELETE CASCADE ON UPDATE )

现在,我尝试在事务中运行它,但它似乎仍然检查外键(我觉得很奇怪)。我实际上可以添加它的唯一方法是在插入期间禁用外键检查,我真的不喜欢。

这里的理想解决方案是这样,在应用程序级别,我所要做的就是:

INSERT INTO related_keywords (keyword_1, keyword_2) VALUES (119250770368532480, 119251038153871360);

并且匹配的行也会自动添加,fk_related_kw_lr外键检查没有问题。

我通常在文档中搜索 MariaDB 和 InnoDB,即使使用 MariaDB 10.x 的新功能,我似乎也无法找到解决方法

有任何想法吗?

标签: mysqlmariadbforeign-keysinnodb

解决方案


  • PK没用

  • UNIQUE需要一个

  • 3 唯一性减慢插入速度。

  • 最佳多对多:http: //mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

  • 我怀疑你是否需要“级联”。

  • 放弃 FK,它们可能带来的麻烦多于其价值。

  • 考虑添加一行,而不是添加 2 行,如下所示。(这可能会有所帮助,也可能会使事情复杂化,具体取决于您对此表的用途。)

      LEAST(1234, 2345),
      GREATEST(1234, 2345)
    

推荐阅读