外键会自动创建索引吗?


389

有人告诉我,如果我对两个表进行外键调用,则该SQL Server将在子表中创建类似于索引的内容。我很难相信这是真的,但是在这方面找不到很多相关的东西。

我问这个的真正原因是因为我们在一个可能包含15个相关表的表的delete语句中,响应时间很慢。我问过我们的数据库专家,他说如果字段上有外键,那么它就像一个索引。您对此有何经验?我应该在所有外键字段上添加索引还是仅仅是不必要的开销?


我和您的数据库专家有相同的理解-实际上FK确实会创建索引。
温妮

9
否-一个FK确实自动创建索引。创建一个是有意义的-但SQL Server 不会自动完成。
marc_s

47
根本不问这个傻!
marc_s

5
如果删除速度很慢,并且要从其他表引用的表中删除,则可能通过索引其他表中的外键来提高性能。这是因为当SQL删除行时,它需要检查行上的引用完整性。为此,显然需要检查是否有其他行引用您要删除的行。
诺埃尔·肯尼迪,

3
我想说一个不知道这是必须的培训人员。数据库人员对性能负责,知道这种事情是他们的工作。这表明完全无能。
HLGEM

Answers:


343

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

但是众所周知的事实是,索引属于任何外键关系的所有列都是很有意义的,因为通过FK关系,您通常需要查找相关表并根据以下内容提取某些行:一个值或一个值范围。

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

请查看Kimberly Tripp的精彩文章“ SQL Server何时停止在外键列上放置索引?”


是的 我很肯定PostgreSQL创建了索引。我很确定MySQL是这样。进行索引很有意义,但这不是必需的。毕竟,如果数据库每次都要进行表扫描,为什么还要引用某些内容呢?
MBCook,2009年

上面提到的这篇文章有点令人困惑,因为SQL Server或任何其他数据库从不在FK上放置索引。
vsingh 2011年

7
@vsingh:这正是本文试图传达-这是一个常见的误解是一个FK自动创建索引-它并没有做到这一点。
marc_s

5
@MBCook不,PostgreSQL不会(至少在9.2或任何以前的版本中)不会在用定义的外键关系的引用方自动创建索引REFERENCES。它会自动UNIQUEPRIMARY KEYUNIQUE约束创建一个索引,并要求在外键关系的UNIQUE引用端存在一个索引,但是对于引用端却没有自动执行任何操作,尽管使自己成为一个好主意。见 stackoverflow.com/questions/970562/...
克雷格·林格

16
这种混乱可能存在因为MySQL的InnoDB都需要,并自动创建当您添加一个外键索引- dev.mysql.com/doc/refman/5.5/en/...
humbads

42

哇,答案遍及整个地图。因此,文档说:

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

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

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

因此,很显然(尽管文档有些混乱)它实际上并没有创建索引。


5
确实-这是对索引的候选 -但不会自动将其创建为一个!其实很清楚,恕我直言:-)
marc_s

4
我发现这部分内容很混乱:“两个表之间的外键关系表明,这两个表已经过优化,可以在使用键作为其条件的查询中进行组合。” 那应该读为“ ...两个表应该被优化...”
Yishai

18

不,外键字段上没有隐式索引,否则Microsoft为什么会说“在外键上创建索引通常很有用”。您的同事可能会将引用表中的外键字段与引用表中的主键混淆了-主键确实会创建隐式索引。


什么是“隐式索引”?这是否仅表示没有创建ab * tree?
Stephanie Page

1
@Stephanie Page:这是我刚刚为这个答案所组成的一个表达式,表示一个自动创建的索引。如果声明主键,SQL Server会自动为其创建索引。但是不要声明外部键(某些其他DB系统会声明)。
Michael Borgwardt 2012年

7

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


6

假设您有一个称为“订单”的大表和一个名为“客户”的小表。从订单到客户都有一个外键。现在,如果删除客户,则Sql Server必须检查是否没有孤立订单;否则,SQL Server必须检查是否有孤立订单。如果存在,则会引发错误。

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

因此,在这种情况下,缓慢删除可以通过缺少索引来解释。尤其是如果Sql Server必须搜索没有索引的15个大表。

PS如果外键具有ON DELETE CASCADE,则Sql Server仍必须搜索订单表,但随后要删除所有引用已删除客户的订单。


的确如此-这就是FK索引确实有意义的原因(大部分时间)
marc_s 2009年

1
大多数时候?似乎是从父级删除的情况。如果您大多数时候都从父母那里删除,那是真的。
Stephanie Page


3

据我所知。外键仅增加了一个约束,即子键中的值也必须在父列中的某个位置表示。这并不是在告诉数据库子键也需要被索引,只是被约束。


3

严格来说,外键与索引完全无关,是的。但是,正如我上面的发言者所指出的那样,有必要创建一个以加快FK查找的速度。实际上,在MySQL中,如果未在FK声明中指定索引,则引擎(InnoDB)会自动为您创建索引。


3

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

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

我认为至少回答了postgres的问题。


抱歉,我没有注意到该问题与MS SQL Server有关,但是在发布答案之后。它可能仍然可以帮助某个人……
Gregor


0

InnoDB要求在外键和引用键上建立索引,以便外键检查可以快速进行,而无需进行表扫描。在引用表中,必须有一个索引,其中外键列以相同的顺序列为第一列。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.