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

Posted

技术标签:

【中文标题】向索引列添加外键会提高性能吗?【英文标题】:Does adding a foreign key to an indexed column boost performance? 【发布时间】:2016-09-08 10:46:21 【问题描述】:

一位同事声称他过去使用外键优化查询。我认为只有在表中插入或更新数据时才使用外键。我不明白如何使用它们来加快搜索速度。

在创建执行计划时,外键如何提供帮助?我错过了什么吗?如果有,那在什么情况下有帮助?

(我们使用 PostgreSQL,我没有太多经验。它的行为是否可能与 Oracle 或 mysql 不同?)

【问题讨论】:

在 PostgreSQL 上,至少一个外键不会提高性能,你是对的,它只是简单地检查 INSERT、UPDATE、DELETE 或 TRUNCATE。但不要更改 SELECT。 索引将提高父表上 DELETE 语句的性能,因为数据库需要检查是否没有更多的子行 - 如果 FK 列被索引,检查会更快跨度> 我不了解 PostgreSQL,但我知道它有助于例如微软SQL。即使现在没有帮助,但将来可能会因为程序(特别是优化器/规划器)仍在积极开发中。 这能回答你的问题吗? Does Foreign Key improve query performance? @philipxy 这是 Microsoft SQL Server 的一个类似问题,而我对 PostgreSQL 很感兴趣。不同的数据库系统有时会以不同的方式运行。 【参考方案1】:

是的,外键确实可以提高查询的性能,但这取决于您使用的数据库以及这些键是否“强制”。

在具有外键的 Oracle 和 SQL Server 中,当读取/加入外键上的多个表时,肯定可以提高性能

为什么?拥有 checked/validated 外键可为查询优化器提供有关 2 个表所具有的关系的额外信息。

知道,当一个子表被内部连接到一个父表时:

    与子表相比,父表的记录数相同或更少子项中的所有键都存在于父项中

这一切都有助于查询优化器估计将要处理的行。对于大多数(如果不是全部)查询优化器来说,正确的估计非常重要。

证明可以通过最近向 Hadoop Hive 添加元数据形式的外键来证明这一普遍事实。此添加的目标是帮助 CBO(基于成本的优化器),this Hive Jira entry 解释说...

此外,在使用事实表时,在外键上有(位图)索引也可以提高 Oracle 中的性能: '应该在一个或多个事实表的每个外键列上建立位图索引'。 请参阅following 链接...

外键,由于显而易见的原因,在插入/更新数据时会花费您额外的费用:与没有 fk 相比,数据库必须完成额外的工作

您可以通过调查解释计划轻松地在 SQL Server 中看到这一点(例如)。

我不知道 Postgresql,但我验证 FK 效果的方法是查看解释计划。启用/禁用/删除 FK 时,它们是否有所不同?

[编辑] 我实际上发现 this证明 FK 可以在 Postgresql 中启用读取性能,但原因有些不同:因为 FK 已启用,示例中的查询可以是更改为更高性能。

【讨论】:

我尝试禁用(甚至删除)各种表上的 FK,但执行计划仍然相同。优化器可以根据索引大小猜测表大小。我不认为 FK 本身可以给它任何它不知道的东西。 嗯,这可能是 Postgresql 在这种行为上与 Oracle / SQL 服务器不同。我真的很确定它在那里有效果。当您通过在父表或子表上包含行限制过滤器来更改查询时,计划是否也与 fk 的启用/禁用相同 我认为这里的重点是“可以提高性能”,对吧?正如您所说,它为优化器提供了更多信息,并且可以更好地估计连接和查询结果基数。当然不能保证,并且在许多情况下不会对优化器产生影响,因为连接列上的统计信息(最大/最小/不同值)将强烈表明子表列中的所有值都存在于父表列中。 此外,如果您想象诸如“从父表中存在行的子表中选择”之类的查询,则可以在存在外键的情况下将其转换为“从子表中选择” . 这个答案的两个要点是错误的和/或误导性的。父表仍然可以比子表有更多的元素,没问题。父母成员不必有孩子,即使从孩子到父母有外键。优化器确实知道子表的所有键都存在于父表中。所以结果介于 1 和子表中的元素数之间。这就像我们没有外键但目标表的字段形成唯一键或主键(这是 postgres 中外键的先决条件,但在其他数据库中不一定)。【参考方案2】:

主键和唯一约束创建相应的索引。但不是 FK 约束:

外键约束声明不会自动创建 引用列的索引。

https://www.postgresql.org/docs/current/static/ddl-constraints.html

所以你是对的。但通常在 FK 上建立索引是个好主意

【讨论】:

【参考方案3】:

如果没有外键索引,则需要扫描整个子表以验证是否有任何行引用了您尝试在父表中删除或更新的键 (即外国)表格

所以是的,在这种特殊情况下,拥有索引将大大提高性能。

【讨论】:

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

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

通过在Oracle子表外键上建立索引提高性能

对连接的结果进行排序时,索引是不是会提高性能

视图的索引字段是不是会提高 MySQL 的性能?

使用 WITH(NOLOCK) 提高性能

SQL插入非常慢[关闭]