【问题标题】:InnoDB - bidirectional many-to-many foreign key checkInnoDB - 双向多对多外键检查
【发布时间】:2021-07-10 20:30:36
【问题描述】:

我正在尝试在表中建立多对多关系:keyword 可以与另一个 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 期间禁用外键检查,我真的不喜欢。

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

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

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

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

  • 暂时禁用单个(多个)约束
  • 将约束检查推迟到事务结束
  • ...并在插入第一个时插入匹配的反向行

有什么想法吗?

【问题讨论】:

    标签: mysql mariadb foreign-keys innodb


    【解决方案1】:
    • 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)
      

    【讨论】:

    • 1.由于 Eloquent 框架中缺乏复合主键支持,因此需要 PK(标记为拐杖)。在这件事上别无选择。 2. 很好地抓住了冗余的唯一键! 3. 你的多对多链接实现了两个不同的表,但我的使用同一个表 4. 需要外键/级联,因为可以删除关键字 5. 自引用外键用于强制两个双向行必须存在。可以用触发器代替它吗?
    • @AustinBurk - 对使用蹩脚的框架表示哀悼。你能在它创建后偷偷摸摸并改变它吗?触发……也许吧。性能是个问题吗?
    猜你喜欢
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-30
    • 2011-01-16
    相关资源
    最近更新 更多