在外键的定义中使用 INDEX DISABLED 关键字

当您定义外键约束时包含可选的 INDEX DISABLED 关键字,可以放置表上的 DML 操作使用与数据库服务器关联的外键的索引。如果您包含 INDEX DISABLED 关键字,则它们必须是 ALTER TABLE 语句的最后规范。

在 ALTER TABLE 语句中定义外键约束

要添加外键约束,您必须在被引用列或子表上拥有 References 权限。如果您拥有父表或有对父表的 Alter 权限,则您可以在该表上创建外键约束并指定您子句作为此约束的所有者。当您持有 DBA 权限时,您可以为其他用户创建外键约束。

当 ALTER TABLE ADD CONSTRAINT 语句在引用子表的一列或一组列上放置外键约束,且该列或该组列没有引用约束或用户定义索引存在时,数据库服务器在指定的列或列组上创建一个内部 B-tree 索引。如果用户定义索引已经存在,则约束共享现有的索引。

如果 ALTER TABLE ADD CONSTRAINT 语句在同一表上定义多个外键,则每个约束需要它自己的 REFERENCES 子句,并为每个约束指定(或忽略)INDEX DISABLED 关键字。

INDEX DISABLED 选项在从集群环境中更新辅助服务器语句中发出的 ALTER TABLE ADD CONSTRAINT 语句中有效。

外键索引可能降低性能的情况

尽管引用约束保护数据完整性,在某些情况下用户定义或系统生成的与数据库服务器关联的外键约束的 B-tree 索引可以降低表(表很大)的操纵数据操作的效率。如果未从父表删除,则该索引不用在子表中锁定行以级联删除。如果子表不需要使用此索引进行查询。在此情境中,并不需要索引,但是这并不意味在子表中修改、删除和插入行的操作中该索引是不重要的。如果禁用对应于外键约束的索引,则在子表上存取数百万行数据的应用可能需要较少的资源。

在这些情况下,ALTER TABLE ADD CONSTRAINT 语句的 INDEX DISABLED 关键字选项提供一个机制,即定义外键时避免大量关联 b-tree 索引的开销。

当您在约束定义的末尾包含 INDEX DISABLED 关键字时,如果没有合适的用户定义索引存在,数据库服务器禁用系统生成的索引。如果在子表上的外键列或(列组)已存在用户定义索引,则数据库服务器禁用该索引。随后的子表上的 DML 存在会在没有索引的情况下实现,而且只需要最小的系统资源以维护和存储该禁用的索引。

Effects of the INDEX DISABLED 关键字的影响

当您在约束定义的末尾包含 INDEX DISABLED 关键字时,如果没有合适的用户定义索引存在,则数据库服务器禁用系统生成的索引。如果在子表上的外键列或(列组)已存在用户定义索引,则数据库服务器禁用该索引。随后的子表上的 DML 存在会在没有索引的情况下实现,而且只需要最小的系统资源以维护和存储该禁用的索引。

这些是您成功使用 INDEX DISABLED 选项添加外键约束时数据库服务器发生的操作:
  • 与外键约束关联的索引被标识。
  • 该索引被禁用,且在系统目录的 sysobjstate 表中标记为禁用。
  • 该物理索引已从数据库中删除。
  • sysfragments 系统目录表变更为显示没有存储分配给此索引。

INDEX DISABLED 关键字对于您定义的外键约束没有影响。数据库服务器强制执行此约束,如果随后对子表或父表的 DML 操作违例了指定外键约束则发出错误。

以下限制应用于约束定义中的 INDEX DISABLED 关键字:
  • INDEX DISABLED 选项只在外键定义中可用。
  • 只有 ALTER TABLE ADD CONSTRAINT 语句支持此语法。如果 CREATE TABLE 或者 ALTER TABLE MODIFY COLUMN 语句的外键定义包含 INDEX DISABLED 关键字,则CREATE TABLE 或者 ALTER TABLE MODIFY COLUMN 语句返回异常。
  • 如果被外键使用的索引正在被另一个约束使用,则数据库服务器返回错误。
  • 如果您在约束定义中包含禁用该外键约束的 DISABLED 关键字,且您还指定了 INDEX DISABLED 关键字则数据库服务器返回错误。如下所示:
 ALTER TABLE child ADD 
              CONSTRAINT(FOREIGN KEY(x1) REFERENCES parent(c1) 
              CONSTRAINT cons_child_x1 DISABLED INDEX DISABLED);

要纠正以上 ALTER TABLE ADD CONSTRAINT 示例中的错误,您必须删除第一个 DISABLED 关键字,或者删除 INDEX DISABLED 关键字。

使用 INDEX DISABLED 创建外键约束的示例

假设在以下示例中的 parent 表和 child 表具有一个主键约束和外键约束,且存储在这些表中您的数据满足下列条件:
  • parent 表只有少量行。
  • child 表由=有百万条行。
  • child 表中外键只有一些基于 parent 表的主键的不同的可能值。
该示例显示了如何使用 ALTER TABLE ADD CONSTRAINT 语句的 INDEX DISABLED 选项。
CREATE TABLE parent(c1 INT, c2 INT, c3 INT);
          CREATE UNIQUE INDEX idx_parent_c1 ON parent(c1);
          ALTER TABLE parent ADD 
          CONSTRAINT PRIMARY KEY(c1) 
          CONSTRAINT cons_parent_c1;
          CREATE TABLE child(x1 INT, x2 INT, x3 VARCHAR(32));
          CREATE INDEX idx_child_x1 ON child(x1);
          
          ALTER TABLE child ADD 
          CONSTRAINT(FOREIGN KEY(x1) REFERENCES parent(c1) 
          CONSTRAINT cons_child_x1 INDEX DISABLED);
在以上示例中,
  • cons_parent_c1parent 表的一个主键约束,
  • cons_child_x1child 表的一个外键约束,
  • idx_parent_c1 是唯一索引,且被 cons_parent_c1 约束共享,
  • 并且 idx_child_x1 是被 cons_child_x1 约束共享的索引。
子表上的数据操纵语言操作(例如:UPDATE 、DELETE 、INSERT 和 MERGE )不能使用被外键约束共享的 idx_child_x1 索引,因为该索引现在是禁用的。

然而,对于某些含有主键和外键依赖的表,查询优化器可能会在执行计划中选择基于 WHERE 子句子表上的其它索引。

如上所述,在外键定义中使用 INDEX DISABLED 选项只有在子表非常大时才可能提高性能,通常在数据仓库应用的情况下。不建议在小的表上使用该语法选项操作。