ChatGPT解决这个技术问题 Extra ChatGPT

外键会自动创建索引吗?

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

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

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

B
Braiam

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

但众所周知的事实是,对属于任何外键关系的所有列进行索引是很有意义的,因为通过 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 端,尽管自己制作一个通常是个好主意。请参阅stackoverflow.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
Y
Yishai

哇,答案都在地图上。所以 Documentation 说:

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

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

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

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


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

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


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

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


有人可以添加一些引用来支持“适用于 Oracle 和 SQL Server”吗?
A
Andomar

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

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

所以在这种情况下,缓慢的删除可以用没有索引来解释。特别是如果 Sql Server 必须搜索 15 个没有索引的大表。

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


没错 - 这就是 FK 上的索引确实很有意义的原因(大多数时候)
大多数时候?似乎这是从父级删除的情况。如果大多数时候你从父母那里删除,我想这是真的。
m
marc_s

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


G
Gregor

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

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

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


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

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


L
Lorenzo Franco Ranucci

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

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

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

MySQL 5.6 也一样。


G
Gandalf

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


L
Luke Puplett

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


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