本文說明 Spanner 中的外部鍵,以及如何使用外部鍵在資料庫中強制執行參照完整性。以下主題可協助您瞭解外鍵和使用方式:
Spanner 中的外鍵總覽
外鍵可定義資料表之間的關係。您可以使用外鍵,確保 Spanner 中這些關係的資料完整性。
假設您是電子商務業務的首席開發人員。您正在設計資料庫,用來處理顧客訂單。資料庫必須儲存每筆訂單、顧客和產品的相關資訊。圖 1 說明應用程式的基本資料庫結構。
圖 1. 訂單處理資料庫的圖表
您定義 Customers 資料表來儲存顧客資訊、Orders 資料表來追蹤所有訂單,以及 Products 資料表來儲存每項產品的資訊。
圖 1 也顯示資料表之間的連結,對應下列實際關係:
顧客下單。
訂購產品。
您決定資料庫要強制執行下列規則,確保系統中的訂單有效。
您無法為不存在的顧客建立訂單。
如果沒有該產品,消費者就無法下單。
強制執行這些規則或限制時,您會維護資料的參照完整性。如果資料庫維護參照完整性,所有嘗試新增無效資料的作業都會失敗,因為這會導致資料間的連結或參照無效。參照完整性可避免使用者發生錯誤。根據預設,Spanner 會使用外鍵強制執行參照完整性。
使用外鍵定義參考完整性
以下再次檢查訂單處理範例,並在設計中加入更多詳細資料,如圖 2 所示。
圖 2:資料庫結構定義圖,其中包含外部鍵
設計畫面現在會顯示每個資料表中的資料欄名稱和類型。Orders資料表也定義了兩個外鍵關係。「FK_CustomerOrder」會預期 Orders 中的所有資料列都有有效的 CustomerId。FK_ProductOrder 外鍵會預期 Orders 資料表中的所有 ProductId 值都有效。下表將這些限制條件對應回您想強制執行的實際規則。
| 外鍵名稱 | 限制 | 實際描述 |
|---|---|---|
| FK_CustomerOrder | 預期 Orders 中的所有資料列都有有效的 CustomerId |
有效顧客下單 |
| FK_ProductOrder | 預期 Orders 中的所有資料列都有有效的 ProductId |
已下單購買有效產品 |
Spanner 會強制執行使用強制執行的外鍵指定的限制。也就是說,如果交易嘗試在 Orders 資料表中插入或更新資料列,但該資料列的 CustomerId 或 ProductId 未在 Customers 和 Products 資料表中找到,Spanner 就會失敗。如果交易嘗試更新或刪除 Customers 和 Products 資料表中的資料列,導致 Orders 資料表中的 ID 無效,交易也會失敗。如要進一步瞭解 Spanner 如何驗證限制,請參閱「交易限制驗證」一節。
與強制執行的外鍵不同,Spanner 不會驗證資訊外鍵的限制。也就是說,如果您在此情境中使用資訊性外鍵,則嘗試在 Orders 資料表中插入或更新含有 CustomerId 或 ProductId 的資料列時,系統不會驗證該資料列,交易也不會失敗。CustomersProducts此外,與強制執行的外鍵不同,資訊外鍵僅適用於 GoogleSQL,不適用於 PostgreSQL。
外鍵特性
以下列出 Spanner 中外鍵的特徵。
定義外鍵的資料表是參照資料表,而外鍵資料欄則是參照資料欄。
外鍵會參照參照資料表的參照資料欄。
如範例所示,您可以為每個外鍵限制命名。如果未指定名稱,Spanner 會為您產生名稱。您可以從 Spanner 的
INFORMATION_SCHEMA查詢產生的名稱。限制名稱的範圍是結構定義,與資料表和索引的名稱相同,且不得與結構定義中的其他名稱重複。參照和被參照的資料欄數必須相同。順序很重要。舉例來說,第一個參照欄會參照第一個參照欄,第二個參照欄則會參照第二個參照欄。
參照欄及其參照的對應欄必須是相同類型。您必須能夠為資料欄建立索引。
您無法在具有
allow_commit_timestamp=true選項的資料欄上建立外部鍵。系統不支援陣列資料欄。
系統不支援 JSON 欄。
外鍵可以參照同一資料表的欄 (自我參照外鍵)。舉例來說,
Employee資料表含有參照資料表EmployeeId資料欄的ManagerId資料欄。外鍵也可以在資料表之間形成循環關係,也就是兩個資料表直接或間接參照彼此。建立外部鍵前,參照的資料表必須存在。也就是說,至少要使用
ALTER TABLE陳述式新增一個外鍵。參照的鍵不得重複。如果外鍵的參照資料欄與參照資料表的主鍵資料欄相符,Spanner 會使用參照資料表的
PRIMARY KEY。如果 Spanner 無法使用參照資料表的主鍵,系統會針對參照資料欄建立UNIQUE NULL_FILTERED INDEX。外鍵不會使用您建立的次要索引。而是建立自己的支援索引。支援索引可用於查詢評估,包括明確的
force_index指令。您可以從 Spanner 的INFORMATION_SCHEMA查詢備份索引的名稱。詳情請參閱「備份索引」。
外鍵類型
外鍵有兩種,分別是強制和資訊。強制執行的外鍵是預設值,可強制執行參照完整性。資訊外鍵不會強制執行參照完整性,最適合用於宣告查詢最佳化的預期邏輯資料模型。詳情請參閱下列「強制執行」和「資訊」外鍵章節,以及「外鍵類型比較」表格。
強制執行的外鍵
強制外鍵是 Spanner 的預設外鍵類型,可強制執行參照完整性。由於強制執行的外鍵會強制執行參照完整性,因此嘗試執行下列操作時會失敗:
如果參照資料表中的外鍵值不存在於參照的資料表中,則無法在參照資料表中新增資料列。
如果參照資料表中的資料列參照了某個資料列,則無法刪除該資料列。
系統會強制執行所有 PostgreSQL 外鍵。GoogleSQL 外鍵預設為強制執行。由於系統預設會強制執行外鍵,因此您不一定要使用 ENFORCED 關鍵字,指定強制執行 GoogleSQL 外鍵。
資訊外鍵
資訊外鍵用於宣告查詢最佳化的預期邏輯資料模型。雖然參照的資料表鍵不得重複,但資訊外鍵不會強制執行參照完整性。如果您想在使用參考完整性資訊外來鍵時,選擇性地驗證參考完整性,則需要在用戶端管理驗證邏輯。詳情請參閱使用資訊性外部鍵。
使用 NOT ENFORCED 關鍵字指定 GoogleSQL 外鍵為資訊性外鍵。PostgreSQL 不支援資訊外鍵。
外鍵類型比較
「強制執行」和「資訊」都有好處。下列各節將比較這兩種外鍵,並提供一些最佳做法。
高階外鍵差異
大致來說,強制和資訊外鍵的差異如下:
違規處置。強制執行的外鍵會驗證並確保寫入作業的參考完整性。資訊外鍵不會驗證或確保參考完整性。
儲存空間。強制執行的外鍵可能需要額外儲存空間,才能在受限資料表上建立支援索引。
寫入處理量。與資訊外鍵相比,強制執行的外鍵在寫入路徑中可能會產生更多額外負擔。
查詢最佳化。這兩種外鍵都可用於查詢最佳化。允許最佳化工具使用資訊外鍵時,如果資料與資訊外鍵關係不符 (例如,如果某些受限鍵在參照資料表中沒有相符的參照鍵),查詢結果可能無法反映實際資料。
外鍵差異表
下表詳細列出強制執行和參考外鍵之間的差異:
| 強制執行的外鍵 | 資訊外鍵 | |
|---|---|---|
| 關鍵字 | ENFORCED |
NOT ENFORCED |
| GoogleSQL 支援 | 可以。GoogleSQL 預設會強制執行外鍵。 | 是。 |
| PostgreSQL 支援 | 可以。PostgreSQL 只能強制執行外部鍵。 | 不會。 |
| 儲存空間 | 強制執行的外鍵最多需要兩個備份索引的儲存空間。 | 資訊型外部索引鍵最多需要一個支援索引的儲存空間。 |
| 視需要為參照資料表資料欄建立支援索引 | 是。 | 是。 |
| 視需要為參照資料表資料欄建立備份索引 | 是。 | 不會。 |
| 支援外鍵動作 | 是。 | 不會。 |
| 驗證及強制執行參照完整性 | 是。 | 否。沒有驗證程序可提升寫入效能,但如果資訊性外鍵用於查詢最佳化,可能會影響查詢結果。您可以使用用戶端驗證或強制執行的外鍵,確保參考完整性。 |
選擇要使用的外鍵類型
您可以參考下列指引,決定要使用的外鍵類型:
建議您先從強制執行的外部鍵開始。強制執行的外部索引鍵可確保資料和邏輯模型隨時保持一致。除非強制執行的外鍵不適用於您的用途,否則建議使用這個選項。
如果符合下列所有條件,建議您考慮使用資訊性外部鍵:
您想在查詢最佳化中使用資訊外鍵所描述的邏輯資料模型。
維持嚴格的參照完整性不切實際,或會大幅影響效能。以下列舉幾個可考慮使用資訊外鍵的情況:
上游資料來源採用最終一致性模型。在這種情況下,來源系統所做的更新可能不會立即反映在 Spanner 中。由於更新可能不會立即生效,外鍵關係可能會出現短暫的不一致。
您的資料包含大量參照關係的參照資料列。更新這些資料列可能會耗用大量資源,因為 Spanner 必須驗證或 (在某些情況下) 刪除與維護參照完整性相關的所有資料列。在這種情況下,更新可能會影響 Spanner 效能,並減緩並行交易的速度。
應用程式可以處理潛在的資料不一致問題,以及這些問題對查詢結果的影響。
使用資訊外鍵
下列主題僅適用於資訊外鍵。如要瞭解適用於資訊性和強制外鍵的主題,請參閱下列內容:
建立含有資訊外鍵的新資料表
您可以使用 DDL 陳述式,在 Spanner 資料庫中建立及移除參考完整性外部鍵 。您可以使用 CREATE TABLE 陳述式,將外鍵新增至新資料表。同樣地,您可以使用 ALTER TABLE 陳述式,從現有資料表新增或移除外來鍵。
下列範例會使用 GoogleSQL 建立具有資訊性外鍵的新資料表。PostgreSQL 不支援資訊外鍵。
GoogleSQL
CREATE TABLE Customers (
CustomerId INT64 NOT NULL,
CustomerName STRING(MAX) NOT NULL,
) PRIMARY KEY(CustomerId);
CREATE TABLE Orders (
OrderId INT64 NOT NULL,
CustomerId INT64 NOT NULL,
Quantity INT64 NOT NULL,
ProductId INT64 NOT NULL,
CONSTRAINT FK_CustomerOrder FOREIGN KEY (CustomerId)
REFERENCES Customers (CustomerId) NOT ENFORCED
) PRIMARY KEY (OrderId);
PostgreSQL
Not Supported
如需建立及管理外鍵的更多範例,請參閱「建立及管理外鍵關係」。如要進一步瞭解 DDL 陳述式,請參閱 DDL 參考資料。
使用資訊性外鍵進行查詢最佳化
查詢最佳化工具可使用強制執行的外部索引鍵和資訊性外部索引鍵,提升查詢效能。使用資訊外鍵可讓您充分運用最佳化的查詢計畫,不必嚴格執行參照完整性,避免產生額外負擔。
如果啟用查詢最佳化工具來運用參考外鍵資訊,請務必瞭解最佳化作業的正確性,取決於資料是否與參考外鍵所描述的邏輯模型一致。如有不一致的情況,查詢結果可能無法反映實際資料。舉例來說,如果受限資料欄中的值在參照資料欄中沒有相符的值,就會發生不一致的情況。
根據預設,查詢最佳化工具會使用 NOT ENFORCED 外鍵。如要變更這項設定,請將資料庫選項 use_unenforced_foreign_key_for_query_optimization 設為 false。以下是 GoogleSQL 範例,可說明這項功能 (PostgreSQL 不提供資訊外鍵):
SET DATABASE OPTIONS (
use_unenforced_foreign_key_for_query_optimization = false
);
布林值查詢陳述式提示 @{use_unenforced_foreign_key} 會覆寫資料庫選項,以控制最佳化工具是否使用外鍵,且是以查詢為單位。NOT ENFORCED排解查詢結果不如預期的問題時,停用這項提示或資料庫選項可能會有幫助。以下說明如何使用 @{use_unenforced_foreign_key}:
@{use_unenforced_foreign_key=false} SELECT Orders.CustomerId
FROM Orders
INNER JOIN Customers ON Customers.CustomerId = Orders.CustomerId;
使用強制執行的外鍵
下列主題僅適用於強制執行的外部鍵。如要瞭解適用於資訊性和強制外鍵的主題,請參閱下列內容:
建立強制執行外鍵的新資料表
您可以使用 DDL,在 Spanner 資料庫中建立、移除及強制執行外鍵。您可以使用 CREATE TABLE 陳述式,將外鍵新增至新資料表。同樣地,您可以使用 ALTER TABLE 陳述式,在現有資料表中加入或移除外鍵。
您可以使用 DDL,在 Spanner 資料庫中建立及移除外鍵。您可以使用 CREATE TABLE 陳述式,將外鍵新增至新資料表。同樣地,您可以使用 ALTER TABLE 陳述式,在現有資料表中新增或移除外鍵。
以下範例說明如何建立新資料表,並強制執行外鍵。
GoogleSQL
CREATE TABLE Customers (
CustomerId INT64 NOT NULL,
CustomerName STRING(MAX) NOT NULL,
) PRIMARY KEY(CustomerId);
CREATE TABLE Orders (
OrderId INT64 NOT NULL,
CustomerId INT64 NOT NULL,
Quantity INT64 NOT NULL,
ProductId INT64 NOT NULL,
CONSTRAINT FK_CustomerOrder FOREIGN KEY (CustomerId)
REFERENCES Customers (CustomerId) ENFORCED
) PRIMARY KEY (OrderId);
PostgreSQL
CREATE TABLE Customers (
CustomerId bigint NOT NULL,
CustomerName character varying(1024) NOT NULL,
PRIMARY KEY(CustomerId)
);
CREATE TABLE Orders (
OrderId BIGINT NOT NULL,
CustomerId BIGINT NOT NULL,
Quantity BIGINT NOT NULL,
ProductId BIGINT NOT NULL,
CONSTRAINT FK_CustomerOrder FOREIGN KEY (CustomerId)
REFERENCES Customers (CustomerId),
PRIMARY KEY (OrderId)
);
如需建立及管理外鍵的更多範例,請參閱「建立及管理外鍵關係」。
外鍵動作
外鍵動作只能在強制執行的外鍵上定義。
外鍵動作會控管受限資料欄在參照資料欄遭到刪除或更新時的處理方式。Spanner 支援使用 ON DELETE CASCADE 動作。使用外鍵 ON DELETE CASCADE
action 時,如果刪除含有參照外鍵的資料列,系統也會在同一筆交易中刪除參照該鍵的所有資料列。
使用 DDL 建立資料庫時,您可以透過動作新增外鍵。使用 CREATE TABLE 陳述式,將外鍵連同動作新增至新資料表。同樣地,您可以使用 ALTER TABLE 陳述式,將外鍵動作新增至現有資料表,或移除外鍵動作。以下範例說明如何建立含有外鍵動作的新資料表。
GoogleSQL
CREATE TABLE ShoppingCarts (
CartId INT64 NOT NULL,
CustomerId INT64 NOT NULL,
CustomerName STRING(MAX) NOT NULL,
CONSTRAINT FKShoppingCartsCustomers FOREIGN KEY(CustomerId, CustomerName)
REFERENCES Customers(CustomerId, CustomerName) ON DELETE CASCADE,
) PRIMARY KEY(CartId);
PostgreSQL
CREATE TABLE ShoppingCarts (
CartId bigint NOT NULL,
CustomerId bigint NOT NULL,
CustomerName character varying(1024) NOT NULL,
PRIMARY KEY(CartId),
CONSTRAINT fkshoppingcartscustomers FOREIGN KEY (CustomerId, CustomerName)
REFERENCES Customers(CustomerId, CustomerName) ON DELETE CASCADE
);
以下列出 Spanner 中外鍵動作的特徵。
外鍵動作為
ON DELETE CASCADE或ON DELETE NO ACTION。您可以查詢
INFORMATION_SCHEMA,找出有動作的外鍵限制。系統不支援在現有外鍵限制上新增外鍵動作。您必須新增含有動作的新外鍵限制。
限制驗證
限制驗證僅適用於強制執行的外部鍵。
Spanner 會在交易提交時,或在交易中後續作業可見寫入效果時,驗證強制執行的外鍵限制。
系統會比對插入參照資料欄的值與參照資料表和參照資料欄的值。系統不會檢查參照值的資料列,因此您可以將這些資料列新增至參照資料表。NULL
嘗試使用 DML 陳述式或 API 更新資料時,Spanner 會驗證所有適用的強制外鍵參照限制。如有任何限制無效,系統會復原所有待處理的變更。
系統會在每個 DML 陳述式之後立即進行驗證。舉例來說,您必須先插入參照的資料列,才能插入參照該資料列的資料列。使用變異 API 時,變異會緩衝處理,直到交易修訂為止。強制執行的外鍵驗證會延後,直到交易提交為止。在這種情況下,可以先插入參照資料列。
系統會評估每筆交易,找出影響強制執行的外部鍵限制的修改。這些評估作業可能需要向伺服器發出額外要求。此外,後端索引也需要額外的處理時間,才能評估交易修改內容並維護索引。每個索引也需要額外儲存空間。
長時間執行的刪除連鎖動作
從參照資料表刪除資料列時,Spanner 必須刪除參照已刪除資料列的參照資料表中的所有資料列。這可能會導致連鎖效應,單一刪除作業會產生數千個其他刪除作業。在資料表中加入外鍵限制條件並使用刪除連鎖動作,或建立含有外鍵限制條件並使用刪除連鎖動作的資料表,可能會拖慢刪除作業。
外鍵刪除連鎖作業超出變動限制
使用外鍵刪除連鎖刪除大量記錄可能會影響效能。這是因為每筆刪除的記錄都會觸發刪除所有相關記錄。如要使用外鍵刪除連鎖刪除大量記錄,請先從子項資料表明確刪除資料列,再從父項資料表刪除資料列。這樣可避免交易因突變限制而失敗。
強制執行的外鍵與資料表交錯比較
Spanner 的資料表交錯功能相當適合用於下列情況:有許多父項子項關係,且子項資料表的主鍵包含父項資料表的主鍵欄。將子項資料列與父項資料列存放在相同位置即可大幅提高效能。
外鍵是應用方式較為廣泛的父項子項關係解決方案,可用於更多用途。外鍵並非僅限於主鍵欄,資料表可以同時含有多組外鍵關係,在某些關係中是父項,在其他關係中則是子項。不過,外鍵關係並不代表資料表位於儲存空間層中的相同位置。
請參考以下範例,其中使用定義如下的 Orders 資料表:
圖 3:資料庫結構定義圖,其中強制執行外部鍵
圖 3 中的設計有一些限制。舉例來說,每個訂單只能包含一個訂單項目。
假設顧客希望每筆訂單都能訂購多項產品,您可以導入 OrderItems 表格,其中包含顧客訂購的每項產品,藉此改善設計。您可以導入另一個強制執行的外鍵,代表 Orders 和 OrderItems 之間的新一對多關係。不過,您也知道自己經常需要對訂單及其各自的訂單項目執行查詢。由於這類資料的共置作業可提升效能,您會想使用 Spanner 的資料表交錯功能建立父項與子項關係。
以下說明如何定義 OrderItems 資料表,並與 Orders 交錯。
GoogleSQL
CREATE TABLE Products (
ProductId INT64 NOT NULL,
Name STRING(256) NOT NULL,
Price FLOAT64
) PRIMARY KEY(ProductId);
CREATE TABLE OrderItems (
OrderId INT64 NOT NULL,
ProductId INT64 NOT NULL,
Quantity INT64 NOT NULL,
FOREIGN KEY (ProductId) REFERENCES Products (ProductId)
) PRIMARY KEY (OrderId, ProductId),
INTERLEAVE IN PARENT Orders ON DELETE CASCADE;
PostgreSQL
CREATE TABLE Products (
ProductId BIGINT NOT NULL,
Name varchar(256) NOT NULL,
Price float8,
PRIMARY KEY(ProductId)
);
CREATE TABLE OrderItems (
OrderId BIGINT NOT NULL,
ProductId BIGINT NOT NULL,
Quantity BIGINT NOT NULL,
FOREIGN KEY (ProductId) REFERENCES Products (ProductId),
PRIMARY KEY (OrderId, ProductId)
) INTERLEAVE IN PARENT Orders ON DELETE CASCADE;
圖 4 是更新後的資料庫結構定義,因為導入了這個新資料表 (OrderItems),並與 Orders 交錯。您也可以在這裡查看這兩個資料表之間的一對多關係。
圖 4:新增交錯的 OrderItems 資料表
在這個設定中,每個訂單可以有多個 OrderItems 項目,且每個訂單的 OrderItems 項目會交錯排列,因此與訂單位於相同位置。以這種方式實體交錯 Orders 和 OrderItems,可提升效能、有效地預先彙整資料表、讓您一併存取相關資料列,同時減少磁碟存取次數。舉例來說,Spanner 可利用主鍵在本機進行彙整,減少存取磁碟的次數並降低網路流量。
如果交易中的變異數超過 80,000,交易就會失敗。這類大型連鎖刪除作業適用於具有「交錯於父項」關係的資料表,但不適用於具有外鍵關係的資料表。如果您有外鍵關係,且需要刪除大量資料列,請務必先從子項資料表明確刪除資料列。
如果您有一個使用者資料表,與另一個資料表有外鍵關係,且從參照資料表刪除資料列會觸發刪除數百萬個資料列,則應使用「交錯於父項」的刪除連鎖動作設計結構定義。
比較表
下表摘要比較了強制執行的外鍵和資料表交錯。您可以根據這項資訊,決定適合設計的項目。
| 父項/子項關係類型 | 資料表交錯 | 強制執行的外鍵 |
|---|---|---|
| 可以使用主鍵 | 是 | 是 |
| 可以使用非主鍵欄 | 否 | 是 |
| 支援的父項人數 | 0 .. 1 | 0 .. N |
| 將父項和子項資料儲存在一起 | 是 | 否 |
| 支援串連刪除 | 是 | 是 |
| 比對模式為空值 | 如果所有參照值與參照值不相異,則通過檢查。 空值與空值不相異,空值與非空值相異。 |
如果任何參照值為空值,則通過驗證。 如果所有參照值皆為非空值,且參照的表格含有值與參照值相等的資料列,則通過驗證。 如果找不到相符的資料列,則驗證失敗。 |
| 強制執行時間 | 使用突變 API 時,每項作業的費用。 使用 DML 時,每個陳述式都會計費。 |
使用變動 API 時,每筆交易的費用。 使用 DML 時,每個陳述式都會計費。 |
| 可移除 | 否。建立資料表交錯後,除非刪除整個子項資料表,否則無法移除。 | 是 |
支援索引
外鍵不會使用使用者建立的索引。而是建立自己的支援索引。強制和資訊外鍵在 Spanner 中建立備份索引的方式不同:
如果是強制執行的外鍵,Spanner 最多可為每個外鍵建立兩個次要支援索引,一個用於參照資料欄,另一個用於參照資料欄。
如果是資訊外鍵,Spanner 可以在需要時,為參照的資料欄建立最多一個支援索引。資訊外鍵不會為參照欄建立支援索引。
無論是強制執行或資訊外鍵,外鍵通常會參照所參照資料表的主鍵,因此通常不需要所參照資料表的索引。因此,資訊性外部索引鍵通常沒有支援索引。如有需要,為參照資料表建立的支援索引為 UNIQUE NULL_FILTERED 索引。如果現有資料違反索引的唯一性限制,就無法建立外鍵。
資訊外鍵沒有參照資料表的支援索引。如果是強制執行的外部鍵,參照資料表的支援索引為 NULL_FILTERED。
如果兩個以上的外部鍵需要相同的支援索引,Spanner 會為每個外部鍵建立單一索引。如果捨棄使用這些索引的外鍵,系統也會捨棄支援索引。您無法變更或捨棄支援索引。
Spanner 會使用每個資料庫的資訊結構定義,儲存支援索引的中繼資料。INFORMATION_SCHEMA.INDEXES 中 SPANNER_IS_MANAGED 值為 true 的資料列,說明備份索引。
除了直接叫用資訊結構定義的 SQL 查詢外,Google Cloud 主控台不會顯示資料庫備份索引的任何資訊。
長時間執行的結構定義變更
在現有資料表中加入強制執行的外鍵,或建立含有外鍵的新資料表,可能會導致作業長時間執行。如果是新資料表,必須等到長時間執行的作業完成後,才能寫入資料表。
下表說明在新的或現有資料表中,強制執行和資訊外鍵會發生什麼情況:
| 資料表類型 | 強制執行的外鍵 | 資訊外鍵 |
|---|---|---|
| 新增 | Spanner 會視需要為每個外鍵回填參照的索引。 | Spanner 會視需要為每個外鍵回填參照的索引。 |
| 現有 | Spanner 會視需要回填參照和被參照的索引。Spanner 也會驗證資料表中的現有資料,確保資料符合外鍵的參照完整性限制。如有任何資料無效,結構定義變更就會失敗。 | Spanner 會視需要回填參照的索引,但不會驗證資料表中的現有資料。 |
系統不支援下列項目:
- 在現有強制執行的外鍵限制中加入外鍵動作。
- 變更現有外鍵的強制執行狀態。
在這兩種情況下,我們建議您改為採取下列做法:
- 新增含有必要動作或強制執行的限制。
- 捨棄舊的限制。
新增限制並捨棄舊限制,可避免發生長時間執行的 Alter Constraint 作業問題。舉例來說,假設您要在現有的外鍵上新增 DELETE CASCADE 動作。使用 ON DELETE CASCADE 動作建立新的外鍵後,這兩項限制的效果都是 DELETE CASCADE 動作。然後即可安全地捨棄舊限制。
如果其他外鍵限制未使用索引,捨棄限制可能會導致捨棄外鍵支援索引。因此,如果先捨棄舊的限制,之後再新增具有動作的相同外鍵限制,可能會導致長時間執行的作業,例如補充作業索引、驗證不重複的索引限制,或驗證外鍵參照限制。
您可以查詢 INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS.SPANNER_STATE,檢查外鍵建立狀態。