【问题标题】:Mysql foreign key by non unique key -- how is that possible?非唯一键的Mysql外键——这怎么可能?
【发布时间】:2011-01-22 15:50:39
【问题描述】:

我正在将 mysql 数据库迁移到 postgres 并偶然发现 DDL 中的以下块(注意:这是我从 mysqldump 得到的):

CREATE TABLE `catalog_property_value` (
  `id` int(10) unsigned NOT NULL,
  `property_id` int(10) unsigned NOT NULL,
  `sort` int(10) unsigned NOT NULL,
  `value_number` decimal(15,5) DEFAULT NULL,
  `value_string` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`,`sort`),
  KEY `FK_catalog_property_value` (`property_id`),
  KEY `NewIndex1` (`id`),
  CONSTRAINT `FK_catalog_property_value` FOREIGN KEY (`property_id`) REFERENCES `catalog_property` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET character_set_client = @saved_cs_client;

CREATE TABLE `catalog_realty_property_value_link` (
  `realty_id` int(10) unsigned NOT NULL,
  `property_id` int(10) unsigned NOT NULL,
  `value_id` int(10) unsigned NOT NULL,
  `dt_is_denormalized` tinyint(1) unsigned NOT NULL,
  PRIMARY KEY (`realty_id`,`property_id`,`value_id`),
  KEY `FK_catalog_realty_property_value_link_property` (`property_id`),
  KEY `FK_catalog_realty_property_value_link_value` (`value_id`),
  CONSTRAINT `FK_catalog_realty_property_value_link_property` FOREIGN KEY (`property_id`) REFERENCES `catalog_property` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FK_catalog_realty_property_value_link_realty` FOREIGN KEY (`realty_id`) REFERENCES `catalog_realty` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `FK_catalog_realty_property_value_link_value` FOREIGN KEY (`value_id`) REFERENCES `catalog_property_value` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

现在,我在这里看到的是,第一个表中唯一的唯一键是 (id, sort) 的组合:

PRIMARY KEY (`id`,`sort`),

但是,第二个表仅通过 id 列引用了第一个表,这不是唯一的!

CONSTRAINT `FK_catalog_realty_property_value_link_value` FOREIGN KEY (`value_id`) REFERENCES `catalog_property_value` (`id`) ON DELETE CASCADE

那么,我在这里做错了什么?这怎么可能?

【问题讨论】:

    标签: mysql database-design foreign-keys


    【解决方案1】:

    根据wikipedia,这是完全合法的:

    引用表中的列 必须是主键或其他 被引用表中的候选键。

    【讨论】:

    • 候选键不是唯一键吗?或者您是说可以使用单个外键来建模多对多关系?我很困惑:(
    • 在这种情况下,引用表中的列根本不是任何键(而是更大键的一部分)。事实上,InnoDB 似乎允许这种情况发生。但这不是标准 SQL。
    • 我不明白 wiki 对外键或候选键的定义如何允许引用非唯一键。
    【解决方案2】:

    最可能的答案是 id 在 catalog_propery_value 表中确实是唯一的,但作者出于未知原因将 PK 声明为超键(id,排序),可能与索引有关,而不是强制唯一性。

    【讨论】:

    • 引擎如何知道 id 是唯一的?它要么被声明为如此,要么没有被声明,在这种情况下,它显然没有被声明为唯一的。
    【解决方案3】:

    innoDB 中 FK 的这种奇怪行为在 manual 中进行了描述。

    对非唯一键或键的外键引用的处理 包含 NULL 值的情况不好 为诸如 UPDATE 之类的操作定义 或删除级联。建议您 使用仅引用的外键 UNIQUE 和 NOT NULL 键。

    PostgreSQL 不接受这种结构,外键必须指向唯一键。

    【讨论】:

      【解决方案4】:

      来自手册:

      偏离 SQL 标准:A 引用的 FOREIGN KEY 约束 非唯一键不是标准 SQL。 它是标准的 InnoDB 扩展 SQL。

      所以看起来 InnoDB 允许非唯一索引作为外键引用的候选者。手册的其他地方指出,您可以在引用的索引中引用列的子集,只要引用的列首先列出并且与主键的顺序相同。

      因此,这个定义在 InnoDB 中是合法的,尽管它不是标准 SQL,至少让我对最初设计者的意图有点困惑。

      Manual page here.

      【讨论】:

      • 如果你看到这个页面:dev.mysql.com/doc/refman/5.0/en/…,第一个要点提到外键必须引用一个索引,该索引首先具有索引列表使用的列,并且与约束指定的顺序相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-10
      • 1970-01-01
      • 1970-01-01
      • 2010-10-09
      • 1970-01-01
      相关资源
      最近更新 更多