简体   繁体   English

MySQL是否隐式地为UNIQUE和FOREIGN KEY约束生成索引,还是我应该显式地创建索引?

[英]Does MySQL generate indices for UNIQUE and FOREIGN KEY constraints implicitly or should I actually create them explicitly?

Let's consider a database of 2 simple tables: tablea has an INT id , a VARCHAR something field and references tableb (containing a same field but with UNIQUE constraint added). 让我们考虑一个包含2个简单表的数据库: tablea具有INT id ,VARCHAR something字段和引用tableb (包含相同字段但添加了UNIQUE约束)。

MySQL Workbench will generate the following code if we use it to design and forward-engineer this schema: 如果我们使用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;

but we can seemingly reach the same effect (same schema of tables, columns and constraints) with more simple, minimalistic code: 但我们似乎可以通过更简单,更简单的代码达到相同的效果(表,列和约束的相同架构):

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;

Is the first version any way better (eg faster) than the second? 第一个版本是否比第二个版本更好(例如更快)? Won't MySQL create the indices mentioned in the first version in the second case as well? 在第二种情况下,MySQL是否也不会创建第一个版本中提到的索引?

In your last chunk as I mentioned in comments and as the manual says, you do not need to explicitly create the FK-related keys in the child tables (the referencing). 正如我在评论中提到的以及手册所说,在最后一个块中,您无需在子表(引用)中显式创建与FK相关的键。 MySQL will auto create them for you if needed based on left-most (or first most as the manual says). 如果需要,MySQL会根据最左边的位置(或按照手册所述的最前面的位置)自动为您创建它们。 A single column index is naturally left-most. 单列索引自然是最左侧的。 For composites, that is multi-column keys, left-most naturally makes some sense. 对于复合材料(即多列键),最左侧自然是有意义的。

It will be very apparent if you run your above, and issue a 如果您运行上面的命令并发出一个

show create table tablea;

If you happen to have a left-most key defined already in a child, and it is usable for the FK relationship, the engine will not create one for you on its own. 如果您恰好在孩子中定义了最左键,并且该键可用于FK关系,则引擎不会自行为您创建一个。

From the manual page entitled Using FOREIGN KEY Constraints 在标题为“ 使用外键约束 ”的手册页中

In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. 在引用表中,必须有一个索引,其中外键列以相同的顺序列为第一列。 Such an index is created on the referencing table automatically if it does not exist. 如果这样的索引不存在,则会在引用表上自动创建。 This index might be silently dropped later, if you create another index that can be used to enforce the foreign key constraint. 如果您创建另一个可用于强制外键约束的索引,则以后可能会静默删除该索引。 index_name, if given, is used as described previously. 如果给定,则使用index_name(如前所述)。

Also as I mentioned in the comment section under your question, the referenced table (the parent), however, must have the necessary left-most keys in place for fast lookup prior to all of this. 同样,正如我在您的问题的注释部分中提到的那样,被引用的表(父表)必须具有必要的最左边的键,以便在所有这些操作之前快速查找。 That key does not need to be a PRIMARY or unique key. 该密钥不必是PRIMARY密钥或唯一密钥。 But it must be available left-most for composites. 但是它必须在复合材料的最左侧可用。 If one is not available in the parent prior to the ALTER TABLE or CREATE TABLE of the child, then the operation fails with 如果在子级的ALTER TABLECREATE TABLE之前的父级中没有一个可用,则该操作将失败并显示

MySQL Error 1215: Cannot add foreign key constraint MySQL错误1215:无法添加外键约束

As for a few quick examples of when a key is created on your behalf (or not) in child tables: 关于在子表中代表(或不代表)何时创建键的几个快速示例:

  1. If you explicitly create a key on col1, and it is used in an FK, a helper key is not created for you. 如果您在col1上显式创建一个密钥,并且该密钥在FK中使用,则不会为您创建帮助密钥。

  2. If you explicitly create a composite key on (a,b,c,d), and you have an FK on (a,b), then a helper key is not created for you. 如果在(a,b,c,d)上显式创建复合键,并且在(a,b)上具有FK,则不会为您创建帮助键。

  3. If you explicitly create a composite key on (a,b,c,d), and you have an FK on (a,c), then a helper key is created for you. 如果在(a,b,c,d)上显式创建复合键,并且在(a,c)上具有FK,则将为您创建一个辅助键。 Because the b gets in the way on the explicit and a new key is required. 因为b妨碍了显式操作,所以需要一个新的键。

  4. If you explicitly create a composite key on (a,b,c,d), and you have an FK on (a,b,c), then a helper key is not created for you. 如果在(a,b,c,d)上显式创建组合键,并且在(a,b,c)上具有FK,则不会为您创建帮助键。 The left-most on the explicit, in the same order, was more than adequate for the requirements of the FK. 以相同的顺序,显式表的最左端足以满足FK的要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM