161

假设我有 2 个表,Products 和 ProductCategories。两个表在 CategoryId 上都有关系。这就是查询。

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category
FROM Products p
INNER JOIN ProductCategories c ON p.CategoryId = c.CategoryId
WHERE c.CategoryId = 1;

当我创建执行计划时,表 ProductCategories 执行集群索引查找,这是预期的。但是对于表产品,它执行集群索引扫描,这让我怀疑。为什么 FK 无助于提高查询性能?

所以我必须在 Products.CategoryId 上创建索引。当我再次创建执行计划时,两个表都执行索引查找。并且估计的子树成本降低了很多。

我的问题是:

  1. 除了 FK 有助于关系约束之外,它还有其他用处吗?它会提高查询性能吗?

  2. 我应该在所有表中的所有 FK 列(喜欢 Products.CategoryId)上创建索引吗?

4

10 回答 10

202

外键是参照完整性工具,而不是性能工具。至少在 SQL Server 中,创建 FK 不会创建关联索引,您应该在所有 FK 字段上创建索引以缩短查找时间。

于 2009-02-03T14:07:29.060 回答
65

外键可以提高(并损害)性能

  1. 如此处所述:外键提高性能

  2. 您应该始终在 FK 列上创建索引以减少查找。SQL Server 不会自动执行此操作。

编辑

由于链接现在似乎已失效(感谢 Chris 的注意),以下显示了为什么外键可以提高(和损害)性能的要点。

外键可以提高性能吗

外键约束提高了读取数据时的性能,但同时降低了插入/修改/删除数据时的性能。

在读取查询的情况下,优化器可以使用外键约束来创建更有效的查询计划,因为外键约束是预先声明的规则。这通常涉及跳过查询计划的某些部分,因为例如优化器可以看到由于外键约束,没有必要执行计划的特定部分。

于 2009-02-03T14:14:07.390 回答
18

外键是用于确保数据库完整性的 DBMS 概念。

任何性能影响/改进都将特定于所使用的数据库技术,并且次要于外键的用途。

SQL Server 中的良好做法是确保所有外键上至少有一个非聚集索引。

我希望这可以为您解决问题,但请随时索取更多详细信息。

于 2009-02-03T14:10:34.310 回答
4

您的最佳性能选择是在您经常使用的字段上使用索引。如果您使用 SQL Server,您可以使用分析器来分析特定数据库并获取输出文件并使用调整向导来接收有关放置索引的位置的建议。我也喜欢使用分析器来清除长时间运行的存储过程,我每周都会发布十大最严重的违规者名单,让人们诚实:D。

于 2009-02-03T15:02:27.607 回答
3

您可以使用它来帮助提高查询效率。它确实允许您在 SQL Server 中重组查询以使用外部联接而不是内部联接,这消除了 sql 服务器必须检查列中是否存在空值的必要性。您不需要输入该限定符,因为外键关系已经为您强制执行。

所以这:

select p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
from Products p
inner join ProductCategories c on
p.CategoryId = c.CategoryId
where c.CategoryId = 1;

变成这样:

 SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
 FROM ProductCategories c 
 LEFT OUTER JOIN Products P ON
 c.CategoryId = p.CategoryId 
 WHERE c.CategoryId = 1;

这不一定会在小型查询中产生巨大的性能,但是当表变大时它可能会更有效。

于 2009-02-03T14:15:42.100 回答
3

我对 SQL Server 了解不多,但在 Oracle 的情况下,拥有外键列会降低数据加载的性能。那是因为数据库需要检查每个插入的数据完整性。是的,正如已经提到的,在外键列上建立索引是一种很好的做法。

于 2009-02-03T15:09:52.927 回答
3

在表中添加外键不会提高性能,只是说如果您在 ProductCategories 表数据库中插入一条记录,将尝试查找外键列的值存在于产品表的主键值中,这个查找,每次在 ProductCategories 表中添加新条目时,操作都会对数据库产生开销。因此,通过添加外键不会提高您的数据库性能,但会注意数据库的完整性。是的,如果您使用外键检查完整性而不是运行许多查询来检查程序中的数据库中是否存在记录,它将提高您的数据库的性能。

于 2011-08-28T09:43:07.560 回答
2

对于 MySQL 5.7,它绝对可以非常好地加速涉及多个连接的查询!

我使用“解释”来理解我的查询,发现我加入了 4-5 个表——根本没有使用任何键。我只为这些表添加了一个外键,结果是加载时间减少了 90%。超过 5 秒的查询现在需要 500 毫秒或更短的时间。

这是一个巨大的进步!

而且,正如其他人所提到的,您可以获得确保关系完整性的额外好处。

除此之外,确保参照完整性也有其自身的性能优势。它具有确保具有外键的表与外表“最新”的二阶效果。假设您有一个用户表和一个评论表,并且您正在对评论表进行一些统计。可能如果您硬删除用户,您也不再需要他们的评论。

于 2018-06-18T22:03:59.660 回答
0

从 SQL Server 2008 开始,外键可以通过影响数据库引擎选择优化查询的方式来影响性能。请参阅以下文章中的 Star Join Heuristics:https ://technet.microsoft.com/en-us/library/2008.04.dwperformance.aspx

于 2017-04-20T01:11:21.317 回答
0

是的,FK可以加速SELECT但减速INSERT/UPDATE/DELETE

SQL Server 使用所有约束(包括 FK)来为 s 构建更好的执行计划SELECT

例如,如果您使用约束运行查询Column1 = X并且X不符合约束,则服务器甚至不会触及表。

P.S. unless the constraint is in "untrusted" state, but that's a whole different story.

P.P.S. However having a foreign key (or other constraints) can slow down INSERT/UPDATE/DELETEs unless you have a non-clustered index on this column

于 2021-06-26T18:10:35.313 回答