为什么 MySQL 在 table 更新期间为外键创建索引

Why MySQL creating indexes for Foreign key during table updation

文档中提到,当您使用 alter table 命令添加外键时,MySQL 不会为外键创建索引,您需要手动创建它。

https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html

The foreign key can be self referential (referring to the same table). When you add a foreign key constraint to a table using ALTER TABLE, remember to create the required indexes first.

但是我使用 alter table 命令在 table 中添加了一个外键,它正在创建索引和约束。

ALTER TABLE `pharmaceuticals_dosage` ADD CONSTRAINT `pharmaceuticals_dosa_as_needed_reason_cod_2ac978bf_fk_human_api` FOREIGN KEY (`as_needed_reason_code_id`) REFERENCES `human_api_code` (`id`);

我认为MySQL官方文档应该没有错,所以它创建索引的原因是什么?

PS: 以上Query由Django migration创建

由于您使用django 创建了外键,它会自动创建数据库索引。 ForeignKey 的文档中提到了它。 来自文档:

A database index is automatically created on the ForeignKey.

您可以通过向该字段添加 db_index=False 来禁用外键。 例如

class SomeModel(models.Model):
    refrence_to_table = models.ForeignKey(SomeTable, db_index=False)
    # other fields

附加文档中的文本:

A database index is automatically created on the ForeignKey. You can disable this by setting db_index to False. You may want to avoid the overhead of an index if you are creating a foreign key for consistency rather than joins, or if you will be creating an alternative index like a partial or multiple column index.

我猜 MySQL 文档指的是当您直接创建外键(从 shell)到其他 table 时。这里 Django 会在创建时生成一个自定义的 sql.

可以查看Django在不同DB操作中使用的Schema

您参考的文档是正确的,但不够清楚。

假设您有 table 名员工。您希望每一行都有一列 manager_id,这是引用另一行的外键,该行是员工的经理。但是出于某种原因,您没有使用 employee_id 作为 table 的主键——您还有另一个主键。

mysql> create table employees (
  id serial primary key, 
  employee_id int, 
  manager_id int
);

您想在 manager_id 上添加外键,引用 employee_id:

mysql> alter table employees add foreign key (manager_id) references employees(employee_id);
ERROR 1215 (HY000): Cannot add foreign key constraint

怎么了? employee_id 上没有索引,但外键只能引用具有索引的列。如果我们在 innodb 状态中获得有关外键错误的详细信息,这会更清楚一点:

mysql> show engine innodb status\G
...
------------------------
LATEST FOREIGN KEY ERROR
------------------------
2019-12-26 10:25:52 0x700005bfb000 Error in foreign key constraint of table test/#sql-159d_8c9:
foreign key (manager_id) references employees(employee_id):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns...
...

您需要先在 employee_id 上创建索引:

mysql> alter table employees add unique key (employee_id);
Query OK, 0 rows affected (0.01 sec)

mysql> alter table employees add foreign key (manager_id) references employees(employee_id);
Query OK, 0 rows affected (0.02 sec)

所以文档说 "remember to create the required indexes first," 是正确的,但不清楚所需索引是否在 referenced 列 (employee_id) 上。您假设文档讨论的是外键列 (manager_id) 上的必需索引。

事实上,创建外键会自动在外键列上创建索引,除非该列上的索引已经存在。