让我们考虑一个包含2个简单表的数据库:tablea
具有INT id
,VARCHAR something
字段和引用tableb
(包含相同字段但具有UNIQUE约束添加)。
如果我们使用它来设计和转发设计这个模式,MySQL Workbench将生成以下代码:
CREATE TABLE IF NOT EXISTS `tableb` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `something_UNIQUE` (`something` ASC))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `tablea` (
`id` INT NOT NULL,
`something` VARCHAR(45) NULL,
`tableb_id` INT NOT NULL,
PRIMARY KEY (`id`, `tableb_id`),
INDEX `fk_tablea_tableb_idx` (`tableb_id` ASC),
CONSTRAINT `fk_tablea_tableb`
FOREIGN KEY (`tableb_id`)
REFERENCES `tableb` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
但我们似乎可以通过更简单,简约的代码达到相同的效果(表,列和约束的相同模式):
CREATE TABLE IF NOT EXISTS `tableb` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NULL,
PRIMARY KEY (`id`),
UNIQUE (`something`)
) ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `tablea` (
`id` INT NOT NULL,
`something` VARCHAR(45) NULL,
`tableb_id` INT NOT NULL,
PRIMARY KEY (`id`, `tableb_id`),
FOREIGN KEY (`tableb_id`) REFERENCES `tableb`(`id`)
) ENGINE = InnoDB;
第一个版本是否比第二个更好(例如更快)? MySQL也不会在第二种情况下创建第一版中提到的索引吗?
答案 0 :(得分:0)
在我在评论中提到的最后一个块中,如手册所述,您不需要在子表(引用)中显式创建与FK相关的键。如果需要,MySQL会根据最左边的情况自动为你创建它们(或者首先是手册中所说的)。单列索引自然是最左边的。对于复合材料,即多列密钥,最左边自然是有道理的。
如果您运行上述内容并发出
,那将非常明显show create table tablea;
如果碰巧在孩子中已经定义了最左键,并且它可用于FK关系,则引擎将不会自己为您创建一个。
从标题为Using FOREIGN KEY Constraints的手册页
在引用表中,必须有一个索引所在的外键 列以相同顺序列为第一列。这样的 如果不是,则会自动在引用表上创建索引 存在。如果您创建,可能会稍后以静默方式删除此索引 另一个可用于强制执行外键约束的索引。 如果给定,则使用index_name,如前所述。
正如我在您的问题的评论部分中提到的那样,引用的表(父级)必须具有必要的最左侧密钥,以便在所有这些之前快速查找。该密钥不需要是PRIMARY
或唯一密钥。但对于复合材料来说,它必须是最左边的。如果在孩子的ALTER TABLE
或CREATE TABLE
之前父母中没有一个,那么操作将失败
MySQL错误1215:无法添加外键约束
关于在子表中代表您(或不代表)创建密钥的几个简单示例:
如果您在col1上明确创建了一个密钥,并且它在FK中使用,则不会为您创建帮助密钥。
如果在(a,b,c,d)上明确创建复合键,并且(a,b)上有FK,则不会为您创建辅助键。
如果在(a,b,c,d)上显式创建复合键,并且(a,c)上有FK,则会为您创建一个辅助键。因为b
会影响显式,并且需要新密钥。
如果在(a,b,c,d)上明确创建复合键,并且(a,b,c)上有FK,则不会为您创建辅助键。显式的最左边,以相同的顺序,足以满足FK的要求。