我需要在 Oracle 的外键上创建索引吗?

Posted

技术标签:

【中文标题】我需要在 Oracle 的外键上创建索引吗?【英文标题】:Do I need to create indexes on foreign keys on Oracle? 【发布时间】:2011-05-06 20:19:18 【问题描述】:

我有一张桌子A 和一张桌子BAB 的主键B_ID 上有一个指向B 的外键。

由于某种原因(我知道有正当理由),当我在键上连接这两个表时,它没有使用索引。

我是否需要在 A.B_ID 上单独创建索引,或者是否应该存在外键来提供这一点?

【问题讨论】:

【参考方案1】:

创建外键不会自动在 A.B_ID 上创建索引。因此,从查询性能的角度来看,在 A.B_ID 上创建单独的索引通常是有意义的。

如果您曾经删除 B 中的行,您肯定希望 A.B_ID 被索引。否则,每次从 B 中删除一行时,Oracle 都必须对 A 进行全表扫描,以确保没有孤立记录(取决于 Oracle 版本,可能还会有额外的锁定影响,但这些影响会减少在较新的 Oracle 版本中)。

【讨论】:

PFK 列呢?例如,如果我有一个多对多关系的中间表,我应该为这个表的两个 PFK 列创建一个索引吗? @Clamari - 如果 C 的主键为 (A_ID, B_ID),则主键将负责从 A 中删除。如果您还希望能够有效地从 B 中删除,你会想要一个关于B_ID的索引。【参考方案2】:

单独的外键约束不提供 Oracle 上的索引 - 必须(并且应该)创建一个。

【讨论】:

在某些数据库上,创建外键约束还会创建索引...即 Jet Engine(MSAccess 文件、Firebird 和 mysql 如果没有明确提到特定的数据库实现,这个答案是没有意义的。当然这个问题被标记为oracle,但是当你从谷歌搜索到这里时,这并不是很明显。 我可以确认 PostgreSQL - 至少在本文发布时 - 不会自动执行此操作。 据我所知,SQL Server (2016, Azure...) 的答案相同。 为什么必须使用 Oracle 在外键上创建索引?请问不这样做会有什么后果?【参考方案3】:

SQL Server 从未自动为外键列添加索引 - 查看 Kim Tripp 的 excellent blog post,了解这个城市神话的背景和历史。

然而,为外键列建立索引通常是个好主意 - 所以是的,我建议确保每个 FK 列都由索引备份;不一定只在这一列上——也许在两列或三列上创建索引是有意义的,其中 FK 列作为第一个列。取决于您的场景和数据。

【讨论】:

【参考方案4】:

仅供参考:Oracle 不会自动创建索引(就像它为唯一约束所做的那样),因为 (a) 不需要强制执行约束,并且 (b) 在某些情况下您不需要.

大多数情况下,然而,您会想要创建一个索引(事实上,在 Oracle Apex 中有一个“未索引外键”的报告)。

每当应用程序需要能够删除父表中的一行或更新 PK 值(这种情况很少见)时,如果不存在索引,DML 就会受到影响,因为它必须锁定整个子表。

我通常选择 not 来添加索引的情况是 FK 指向定义列域的“静态数据”表(例如状态代码表),其中父表上的更新和删除永远不会由应用程序直接完成。但是,如果在列上添加索引可以为应用程序中的重要查询带来好处,那么索引仍然是一个好主意。

【讨论】:

【参考方案5】:

与任何与性能有关的事情一样,它取决于许多因素,并且没有灵丹妙药,例如在非常高的活动环境中,索引的维护可能是不可接受的。

这里最突出的似乎是选择性:如果索引中的值高度重复,那么删除索引(如果可能)并允许表扫描可能会提供更好的性能。

【讨论】:

【参考方案6】:

出于性能原因,应创建索引。用于主表的删除操作(检查您要删除的记录是否未被使用)和通常涉及外键的连接。只有少数表(我不在日志中创建它们)可能不需要索引,但在这种情况下,您可能也不需要外键约束。

但是

有些数据库已经自动在外键上创建索引。 Jet 引擎(Microsoft 访问文件) 火鸟 MySQL

确定

SQL 服务器 甲骨文

没有

【讨论】:

感谢您提到 FIrebird SQL 会自动执行此操作。这正是我要寻找的重点。【参考方案7】:

UNIQUE、PRIMARY KEY 和 FOREIGN KEY 约束生成强制或“支持”约束的索引(有时称为支持索引)。 PRIMARY KEY 约束生成唯一索引。 FOREIGN KEY 约束生成非唯一索引。如果所有列都不可为空,则 UNIQUE 约束会生成唯一索引,如果一个或多个列都可以为空,则它们会生成非唯一索引。因此,如果一列或一组列具有 UNIQUE、PRIMARY KEY 或 FOREIGN KEY 约束,则无需为这些列创建索引以提高性能。

【讨论】:

docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj13590.html 您链接到的文档适用于嵌入式 Java 数据库 Derby,而不适用于 Oracle。

以上是关于我需要在 Oracle 的外键上创建索引吗?的主要内容,如果未能解决你的问题,请参考以下文章

1Z0-051-DDL-2简单索引的创建和删除

Oracle 中的外键创建问题

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

在SQL中如何创建外键约束?

Oracle一个字段的的外键可以当另一个字段的主键吗

具有默认值的外键上的 Django 1.7 迁移错误