外键会提高查询性能吗?

Posted

技术标签:

【中文标题】外键会提高查询性能吗?【英文标题】:Does Foreign Key improve query performance? 【发布时间】:2010-10-05 03:57:01 【问题描述】:

假设我有 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 执行集群索引查找,这是预期的。但是对于表 Products,它执行集群索引扫描,这让我怀疑。为什么 FK 无助于提高查询性能?

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

我的问题是:

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

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

好的模型(通常)表现更好。 “外键是一种关系完整性工具”——请谨慎使用“关系”一词。外键是一个数据库概念,是参照完整性约束的简写。它们不是关系模型的一部分。我猜你打错字了。 @Kenny 通常是的,但有时更好的模型成本更高。恰当的例子:外键导致更多的处理发生,而不是更少。 外键 do 提高了性能,至少在 mysql 中是这样。而且,您是对的,创建 FK 不会创建索引; FK的创建需要索引 这个答案几乎没用,因为它没有回答问题。很高兴知道外键不打算对性能产生(积极的)影响,但问题是关于现实,而不是意图。【参考方案2】:

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

    如此处所述:Foreign keys boost performance

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

编辑

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

Can Foreign key improve performance

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

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

【讨论】:

这是一个链接,详细说明了它们会降低性能的方式devx.com/getHelpOn/10MinuteSolution/16595/0/page/2 这是有道理的,但您只会遇到大量删除语句。也许结论应该是,在 OLAP 环境中,非索引 FK 会提高性能,而在 OLTP 环境中,它会降低性能。 此答案中的链接已失效。这是不幸的,因为这是 FK 提高性能的唯一论据。 @ChrisMoschini - 直到现在我才注意到你的评论。正如您所提到的,该链接已失效,但我发布的新链接(带有详细信息)中提到了它的要点。 Wayback Machine link 赢得胜利!这篇文章也可以在 SQLMag.com 上找到,here。【参考方案3】:

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

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

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

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

【讨论】:

@Kenny Evitt 如果您没有完整性,您的数据将毫无用处。我发现它很容易卖。 @HLGEM 偶尔获得404 error 仍然是可以忍受的。使用更便宜的资源和不太复杂的系统获得卓越的吞吐量作为回报,现在也很容易销售。您可能对C.A.P. theorem 感兴趣。 @Daniel Dinnyes,数据完整性与 404 错误无关。这是关于拥有可用的数据。例如,由于开发人员的无能,它不会丢失报告的订单和财务数据。没有理由不使用外键。 我同意 HLGEM。让您的代码处理完整性并不总是一个好主意。数据通常用于做出决策,但如果数据损坏,则决策将不准确。 “外键是一种关系完整性工具”——请谨慎使用“关系”一词。外键是一个数据库概念,是参照完整性约束的简写。它们不是关系模型的一部分。我猜你打错字了。【参考方案4】:

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

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:

您可以使用它来帮助提高查询效率。它确实允许您在 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;

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

【讨论】:

不仅外部联接通常不如效率低于内部联接 (***.com/a/2726683/155892),而且现在您的查询具有误导性:您依赖数据库隐式地转换外部联接加入内部连接(恢复性能),而不是明确地这样做【参考方案8】:

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

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

这是一个巨大的进步!

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

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

【讨论】:

在添加之前,表是否具有生成外键所需的索引?【参考方案9】:

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

【讨论】:

【参考方案10】:

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

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

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

附:除非约束在"untrusted" state,但那是完全不同的故事。

附言但是,拥有外键(或其他约束)可能会减慢 INSERT/UPDATE/DELETEs,除非您在此列上有非聚集索引

【讨论】:

以上是关于外键会提高查询性能吗?的主要内容,如果未能解决你的问题,请参考以下文章

外键会自动创建索引吗?

外键会自动创建索引吗?

将数据从 EBS 移动到临时存储会提高 MySQL 查询性能吗?

Redshift在建表时有sortkey选项来提高查询性能,DolphinDB有类似的机制吗?

将 SQL 查询转换为 PL/SQL 可以提高 Oracle 12c 中的性能吗? [关闭]

为啥表上存在主键会显着提高列存储索引的性能?