外键会自动创建索引吗?

Posted

技术标签:

【中文标题】外键会自动创建索引吗?【英文标题】:Does a foreign key automatically create an index? 【发布时间】:2010-10-24 14:01:00 【问题描述】:

有人告诉我,如果我将两个表作为外键,SQL Server 将在子表中创建类似于索引的东西。我很难相信这是真的,但找不到与此相关的太多内容。

我提出这个问题的真正原因是,我们在针对可能有 15 个相关表的表的删除语句中遇到了一些非常缓慢的响应时间。我问过我们的数据库人员,他说如果字段上有外键,那么它就像一个索引。您对此有何经验?我应该在所有外键字段上添加索引还是它们只是不必要的开销?

【问题讨论】:

我和你的数据库人有同样的理解——FKs 实际上创建了一个索引。 否 - FK 确实 NOT 自动创建索引。创建一个是有意义的 - 但它由 SQL Server 自动完成。 问这个问题一点也不傻! 如果您的删除速度较慢,并且您要从中删除的表被其他表引用,您可能会通过索引 other 表中的外键来提高性能。这是因为当 SQL 删除一行时,它需要检查该行的引用完整性。为此,它显然需要检查是否存在引用您要删除的行的其他行。 我想说一个不知道这一点的数据库人员一定非常需要培训。数据库人员对性能负责,了解这类事情是他们的工作。这表明严重无能。 【参考方案1】:

这取决于。如果您不自己创建索引,则会在 mysql 上创建索引:

MySQL 要求对外键列进行索引;如果您创建一个具有外键约束但在给定列上没有索引的表,则会创建一个索引。

来源:https://dev.mysql.com/doc/refman/8.0/en/constraint-foreign-key.html

MySQL 5.6 也一样。

【讨论】:

【参考方案2】:

外键是一个约束,是两个表之间的关系——与索引本身无关。

但众所周知,对属于任何外键关系的所有列进行索引是很有意义的,因为通过 FK 关系,您通常需要查找相关表并提取某些基于单个值或一系列值的行。

因此,对 FK 中涉及的任何列进行索引是很有意义的,但 FK 本身并不是索引。

查看 Kimberly Tripp 的优秀文章 "When did SQL Server stop putting indexes on Foreign Key columns?"。

【讨论】:

是的。我很肯定 PostgreSQL 创建了一个索引。我很确定 MySQL 可以。制作索引很有意义,但这不是必需的。毕竟,如果数据库每次去查找它都必须进行表扫描,为什么还要引用一些东西呢? @vsingh:这正是本文试图传达的内容 - FK 自动创建索引是一种常见的误解 - 它确实不会这样做那个。 @MBCook 不,PostgreSQL 不会(至少在 9.2 或任何先前版本中)自动在用 REFERENCES 定义的外键关系的引用端创建索引.它会自动为PRIMARY KEYUNIQUE 约束创建UNIQUE 索引,并要求为外键关系的referenced 端提供UNIQUE 索引,但不会自动执行任何操作对于 reference 端,尽管自己制作一个通常是个好主意。见***.com/questions/970562/… 可能存在混淆,因为 MySQL InnoDB 在添加外键时需要并自动创建索引 - dev.mysql.com/doc/refman/5.5/en/… @Daan:如果在选择中使用了最左侧的 n 列,则可以使用任何复合索引。所以对于(books_id, users_id),如果您只搜索books_id,则可能会被使用;或books_idusers_id。它将 NOT 但是如果您需要搜索 only users_id【参考方案3】:

我注意到指向 MSSQL 的 Entity Framework 6.1 确实会自动在外键上添加索引。

【讨论】:

如果您手动将列标记为索引的一部分(例如,如果您正在为多个成员创建复合索引),我不相信它会这样做【参考方案4】:

外键不创建索引。只有备用键约束(唯一)和主键约束创建索引。在 Oracle 和 SQL Server 中也是如此。

【讨论】:

【参考方案5】:

在 PostgeSql 中,如果您点击 \d 表名,您可以自己检查索引

您将看到已在具有主键和唯一约束的列上自动创建 btree 索引,但不会在具有外键的列上创建。

我认为至少对于 postgres 来说,这回答了你的问题。

【讨论】:

对不起,我没有注意到这个问题与 MS SQL Server 有关,但在发布了答案之后。它可能仍然可以帮助某人......【参考方案6】:

SQL Server 会自动为主键创建索引,但不会为外键创建索引。为外键创建索引。这可能是值得的开销。

【讨论】:

【参考方案7】:

假设您有一张名为 orders 的大桌子和一张名为 customers 的小桌子。从订单到客户有一个外键。现在如果你删除一个客户,Sql Server 必须检查没有孤单;如果有,则会引发错误。

要检查是否有任何订单,Sql Server 必须搜索大订单表。现在如果有索引,搜索会很快;如果没有,搜索会很慢。

因此,在这种情况下,删除缓慢可能是因为没有索引。特别是如果 Sql Server 必须搜索 15 个没有索引的大表。

附:如果外键有 ON DELETE CASCADE,Sql Server 仍然需要搜索订单表,然后删除所有引用已删除客户的订单。

【讨论】:

没错 - 这就是 FK 上的索引确实很有意义的原因(大部分时间) 大部分时间?似乎这是从父级删除的情况。如果大多数时候你从父母那里删除,我想这是真的。【参考方案8】:

严格来说,外键与索引完全无关,是的。但是,正如我上面的发言者所指出的,创建一个来加速 FK 查找是有意义的。事实上,在 MySQL 中,如果您没有在 FK 声明中指定索引,引擎 (InnoDB) 会自动为您创建它。

【讨论】:

【参考方案9】:

哇,答案无处不在。所以Documentation 说:

FOREIGN KEY 约束是索引的候选,因为:

使用相关表中的 FOREIGN KEY 约束检查对 PRIMARY KEY 约束的更改。

通过将一个表的 FOREIGN KEY 约束中的列与主键或唯一键列相匹配,在查询中组合来自相关表的数据时,外键列通常用于连接条件在另一张桌子上。索引允许 Microsoft® SQL Server™ 2000 在外键表中快速查找相关数据。但是,创建此索引不是必需的。即使两个表之间没有定义 PRIMARY KEY 或 FOREIGN KEY 约束,也可以组合来自两个相关表的数据,但是两个表之间的外键关系表明这两个表已被优化为在使用键作为查询的查询中组合它的标准。

所以看起来很清楚(尽管文档有点混乱)它实际上并没有创建索引。

【讨论】:

完全正确 - 它是索引的 CANDIDATE - 但它不会自动创建为一个!实际上很清楚,恕我直言:-) 我发现这部分很混乱:“两个表之间的外键关系表明这两个表已经过优化,可以在使用键作为条件的查询中组合。”那应该是“......应该优化两个表......”【参考方案10】:

不,外键字段没有隐式索引,否则微软为什么会说"Creating an index on a foreign key is often useful"。您的同事可能会将引用表中的外键字段与被引用表中的主键混淆 - 主键确实会创建隐式索引。

【讨论】:

什么是“隐式索引”?它是否只是暗示有一个 b*tree 而没有创建它? @Stephanie Page:这是我刚刚为这个答案编造的一个表达式,表示自动创建的索引。如果您声明主键,SQL Server 会自动为其创建和索引。但不是 ff 你声明了一个外键(其他一些数据库系统这样做)。【参考方案11】:

据我所知。外键只增加了一个约束,即子键中的值也可以在父列的某处表示。它并没有告诉数据库子键也需要被索引,只是受到约束。

【讨论】:

以上是关于外键会自动创建索引吗?的主要内容,如果未能解决你的问题,请参考以下文章

向索引列添加外键会提高性能吗?

Django 会自动为外键列生成索引吗?

Oracle外键需要建索引吗?

我需要在 Oracle 的外键上创建索引吗?

sql创建表格语句主键自动增加

外键会提高查询性能吗?