淺談數據庫主外鍵約束

主鍵約束
數據庫

表一般具備包含惟一標識表中每一行的值的一列或一組列。 這樣的一列或多列稱爲表的主鍵 (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 觸發器。

相關文章
相關標籤/搜索