浅谈数据库主外键约束

主键约束
数据库

表一般具备包含惟一标识表中每一行的值的一列或一组列。 这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性。 因为主键约束可保证数据的惟一性,所以常常对标识列定义这种约束。优化

若是为表指定了主键约束,数据库引擎将经过为主键列自动建立惟一索引来强制数据的惟一性。 当在查询中使用主键时,此索引还容许对数据进行快速访问。 若是对多列定义了主键约束,则一列中的值可能会重复,但来自主键约束定义中全部列的值的任何组合必须惟一。spa

以下图所示,Purchasing.ProductVendor 表中的 ProductID 和 VendorID 列构成了针对此表的复合主键约束。 这确保了 ProductVendor 表中的每一个行都具备 ProductID 和VendorID 的一个惟一组合。 这样能够防止插入重复的行。对象

组合 PRIMARY KEY 约束

  • 一个表只能包含一个主键约束。排序

  • 主键不能超过 16 列且总密钥长度不能超过 900 个字节。递归

  • 由主键约束生成的索引不会使表中的索引数超过 999 个非汇集索引和 1 个汇集索引。索引

  • 若是没有为主键约束指定汇集或非汇集索引,而且表中没有汇集索引,则使用汇集索引。ci

  • 在主键约束中定义的全部列都必须定义为不为 Null。 若是没有指定为 Null 性,则参与主键约束的全部列的为 Null 性都将设置为不为 Null。get

  • 若是在 CLR 用户定义类型的列中定义主键,则该类型的实现必须支持二进制排序。it

外键约束

外键 (FK) 是用于在两个表中的数据之间创建和增强连接的一列或多列的组合,可控制可在外键表中存储的数据。 在外键引用中,当包含一个表的主键值的一个或多个列被另外一个表中的一个或多个列引用时,就在这两个表之间建立了连接。 这个列就成为第二个表的外键。

例如,由于销售订单和销售人员之间存在一种逻辑关系,因此 Sales.SalesOrderHeader 表含有一个指向 Sales.SalesPerson 表的外键连接。 SalesOrderHeader 表中的SalesPersonID 列与 SalesPerson 表中的主键列相对应。 SalesOrderHeader 表中的 SalesPersonID 列是指向 SalesPerson 表的外键。 经过建立此外键关系,若是 SalesPerson 表中不存在外键关系,则 SalesPersonID 的值将没法插入到 SalesOrderHeader 表。

外键约束的索引

与主键约束不一样,建立外键约束不会自动建立对应的索引。 可是因为如下缘由,对外键手动建立索引一般是有用的:

  • 当在查询中组合相关表中的数据时,常常在联接条件中使用外键列,方法是将一个表的外键约束中的一列或多列与另外一个表中的主键列或惟一键列匹配。 索引使 数据库引擎能够在外键表中快速查找相关数据。 可是,建立此索引并非必需的。 即便没有对两个相关表定义主键或外键约束,也能够对来自这两个表中的数据进行组合,但两个表间的外键关系说明已用其键做为条件对其进行了优化,以便组合到查询中。

  • 对主键约束的更改可由相关表中的外键约束检查。

引用完整性

尽管外键约束的主要目的是控制能够存储在外键表中的数据,但它还能够控制对主键表中数据的更改。 例如,若是在 Sales.SalesPerson 表中删除一个销售人员行,而这个销售人员的 ID 由 Sales.SalesOrderHeader 表中的销售订单使用,则这两个表之间关联的完整性将被破坏;SalesOrderHeader 表中删除的销售人员的销售订单由于与 SalesPerson 表中的数据没有连接而变得孤立了。

外键约束防止这种状况发生。 若是主键表中数据的更改使之与外键表中数据的连接失效,则这种更改将没法实现,从而确保了引用完整性。 若是试图删除主键表中的行或更改主键值,而该主键值与另外一个表的外键约束中的值相对应,则该操做将失败。 若要成功更改或删除外键约束中的行,必须先在外键表中删除或更改外键数据,这会将外键连接到不一样的主键数据。

级联引用完整性

经过使用级联引用完整性约束,您能够定义当用户试图删除或更新现有外键指向的键时,数据库引擎 执行的操做。 能够定义如下级联操做。

  • NO ACTION

  • 数据库引擎将引起错误,此时将回滚对父表中行的删除或更新操做。

  • CASCADE

  • 若是在父表中更新或删除了一行,则将在引用表中更新或删除相应的行。 若是 timestamp 列是外键或被引用键的一部分,则不能指定 CASCADE。 不能为带有 INSTEAD OF DELETE 触发器的表指定 ON DELETE CASCADE。 对于带有 INSTEAD OF UPDATE 触发器的表,不能指定 ON UPDATE CASCADE。

  • SET NULL

  • 若是更新或删除了父表中的相应行,则会将构成外键的全部值设置为 NULL。 若要执行此约束,外键列必须可为空值。 没法为带有 INSTEAD OF UPDATE 触发器的表指定。

  • SET DEFAULT

  • 若是更新或删除了父表中对应的行,则组成外键的全部值都将设置为默认值。 若要执行此约束,全部外键列都必须有默认定义。 若是某个列可为空值,而且未设置显式的默认值,则将使用 NULL 做为该列的隐式默认值。 没法为带有 INSTEAD OF UPDATE 触发器的表指定。

可将 CASCADE、SET NULL、SET DEFAULT 和 NO ACTION 在相互存在引用关系的表上进行组合。 若是数据库引擎遇到 NO ACTION,它将中止并回滚相关的 CASCADE、SET NULL 和 SET DEFAULT 操做。 若是 DELETE 语句致使 CASCADE、SET NULL、SET DEFAULT 和 NO ACTION 操做的组合,则在数据库引擎检查全部 NO ACTION 前,将应用全部 CASCADE、SET NULL 和 SET DEFAULT 操做。

触发器和级联引用操做

级联引用操做按下列方式激发 AFTER UPDATE 或 AFTER DELETE 触发器:

  • 首先执行由原始 DELETE 或 UPDATE 直接致使的全部级联引用操做。

  • 若是为受影响的表定义了任何 AFTER 触发器,则在执行完全部级联操做后激发这些触发器。 这些触发器将按与级联操做相反的顺序激发。 若是单个表中存在多个触发器,它们将按随机顺序激发,除非专门为表指定了第一个或最后一个触发器。 此顺序是使用 sp_settriggerorder 指定的。

  • 若是多个级联链源自做为 UPDATE 或 DELETE 操做的直接目标的表,则这些链激发各自的触发器的顺序是不定的。 可是,只有当一条链激发其全部的触发器以后,另外一条链才开始激发。

  • 不论是否影响任何行,做为 UPDATE 或 DELETE 操做的直接目标的表上的 AFTER 触发器都会激发。 在这种状况下,级联操做不会影响其余表。

  • 若是上面的任一触发器对其余表执行 UPDATE 或 DELETE 操做,这些操做将启动辅助级联链。 在激发全部主链上的全部触发器后,会分别为每一个 UPDATE 或 DELETE 操做处理这些辅助链。 可能会为后续的 UPDATE 或 DELETE 操做递归重复此过程。

  • 在触发器内执行 CREATE、ALTER、DELETE 或其余数据定义语言 (DDL) 操做可能会致使 DDL 触发器激发。 以后,就可能会执行启动其余级联链和触发器的 DELETE 或 UPDATE 操做。

  • 若是任何特定的级联引用操做链中产生错误,都将引起错误而且不会在该链中激发任何 AFTER 触发器,而建立该链的 DELETE 或 UPDATE 操做将回滚。

  • 具备 INSTEAD OF 触发器的表不能同时具备指定级联操做的 REFERENCES 子句。 可是,级联操做目标表的 AFTER 触发器可对另外一个表或视图执行 INSERT、UPDATE 或 DELETE 语句,这将激发为该对象定义的 INSTEAD OF 触发器。

相关文章
相关标签/搜索