本文說明 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 在 Customers 和 Products 資料表中找不到時,系統不會驗證該交易,且交易不會失敗。此外,與強制執行的外鍵不同,資訊外鍵僅由 GoogleSQL 支援,PostgreSQL 不支援。
外鍵特性
以下是 Spanner 外鍵的特性清單。
定義外鍵的資料表是「參照」資料表,外鍵資料欄則是「參照」資料欄。
外鍵會參照「參照」資料表的「參照」資料欄。
如範例所示,您可以為每個外鍵限制命名。如未指定名稱,Spanner 會為您產生名稱。您可以從 Spanner 的
INFORMATION_SCHEMA查詢產生的名稱。限制名稱的範圍與資料表和索引的名稱相同,且在結構定義中不得重複。參照資料欄和被參照資料欄的數量必須相同。順序很重要。例如,第一個參照欄參照第一個被參照欄,第二個參照欄參照第二個被參照欄。
參照資料欄和參照目標資料欄必須是相同類型。您必須能夠為資料欄建立索引。
您無法在具有
allow_commit_timestamp=true選項的資料欄上建立外鍵。不支援陣列資料欄。
不支援 JSON 資料欄。
外鍵可以參照同一資料表的資料欄 (自我參照外鍵)。例如,
Employee資料表中的ManagerId資料欄參照了該資料表的EmployeeId資料欄。外鍵也可以在資料表之間形成循環關係,其中兩個資料表會直接或間接相互參照。建立外鍵前,參照的資料表必須存在。也就是說,至少須使用
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 SET NULL 動作。
使用 ON DELETE CASCADE 動作時,如果刪除外鍵參照的資料列,則參照該鍵的所有資料列也會在同一筆交易中刪除。
使用 ON DELETE SET NULL 動作時,如果刪除外鍵參照的資料列,則在同一筆交易中,參照該鍵的所有資料列中的參照資料欄都會設為 NULL。
使用 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 SET NULL或ON DELETE NO ACTION。您無法在參照資料表的參照資料欄 (屬於主鍵、標示為
NOT NULL或產生的資料欄) 上使用ON DELETE SET NULL。您可以查詢
INFORMATION_SCHEMA,找出具有動作的外鍵限制。不支援在現有的外鍵限制上新增外鍵動作。您必須新增外鍵限制,並指定動作。
限制驗證
限制驗證僅適用於強制執行的外鍵。
Spanner 會在提交交易時,或在交易中後續作業可看到寫入效果時,驗證強制執行的外鍵限制。
插入參照資料欄的值會與參照資料表和參照資料欄的值進行比對。系統不會檢查含有 NULL 參照值的資料列,也就是說,您可以將這些資料列新增至參照資料表。
使用 DML 陳述式或 API 嘗試更新資料時,Spanner 會驗證所有適用的強制執行外鍵參照限制。如果有任何限制無效,所有待變更項目都會復原。
系統會在每個 DML 陳述式後立即進行驗證。例如,您必須先插入參照資料列,才能插入參照資料列。使用異動 API 時,異動會緩衝處理,直到交易提交為止。強制執行的外鍵驗證會延遲到交易提交後才執行。在這種情況下,可以先插入參照列。
系統會評估每筆交易,確認是否有任何修改會影響強制執行的外鍵限制。這些評估作業可能需要向伺服器提出額外要求。支援索引也需要額外的處理時間,才能評估交易修改及維護索引。每個索引也需要額外的儲存空間。
長時間執行的刪除串聯動作
從參照資料表刪除資料列時,Spanner 必須刪除參照資料表中參照已刪除資料列的所有資料列。這可能會導致連鎖效應,單一刪除作業會導致數千項其他刪除作業。如果將含有刪除串聯動作的外鍵限制新增至資料表,或建立含有刪除串聯動作的外鍵限制資料表,可能會拖慢刪除作業。
長時間執行的刪除作業,將動作設為空值
當您從參照資料表刪除資料列時,Spanner 會將參照資料欄設為 NULL,藉此更新參照資料表中所有具有 ON DELETE SET NULL 動作的資料列。這可能會導致連鎖效應,單一刪除作業會導致數千個更新作業。在資料表中新增 ON DELETE SET NULL 外鍵限制,或建立含有這類限制的資料表,可能會降低刪除作業的速度。
外鍵刪除串聯作業超出異動限制
使用外鍵刪除串聯刪除大量記錄,可能會影響效能。這是因為每刪除一筆記錄,就會刪除所有相關記錄。如需使用外鍵刪除串聯刪除大量記錄,請先明確刪除子資料表中的資料列,再刪除父項資料表中的資料列。這可避免交易因異動限制而失敗。
外鍵刪除設為空值時,超出異動限制
使用外鍵 ON DELETE SET NULL 動作刪除會觸發大量更新的資料列,可能會影響效能。這是因為參照資料表中每刪除一個資料列,就會觸發參照資料表中所有參照該資料列的資料列更新。如要刪除會使用 ON DELETE SET NULL 觸發多項更新的資料列,請先明確將參照資料列更新為 NULL,或先刪除參照資料列,再刪除被參照的資料列。這種做法可避免交易因異動限制而失敗。
外鍵刪除動作的資源用量
ON DELETE CASCADE 和 ON DELETE SET NULL 的資源和異動費用會因結構定義而異:
- 基礎資料表異動:
ON DELETE SET NULL會更新個別資料欄,因此每個更新的參照資料列會計為多項異動 (資料列索引鍵和設為NULL的每個資料欄)。ON DELETE CASCADE會計為每個刪除的資料列一項異動,或當參照資料欄是參照資料表主鍵的前置字串時,每個刪除的索引鍵範圍一項異動。 - 索引異動:這兩項動作都會在外鍵的支援索引上,對每個資料列使用一項刪除異動。對於參照資料表上的其他次要索引,
ON DELETE SET NULL只會修改包含參照資料欄的索引,而ON DELETE CASCADE則會刪除資料表上每個次要索引的項目。 - 讀取:
ON DELETE SET NULL一律會讀取外鍵支援索引,找出相符的資料列。如果參照資料欄是參照資料表主鍵的前置字串,ON DELETE CASCADE就能略過這項讀取作業,直接刪除索引鍵範圍。 - 串聯:
ON DELETE SET NULL絕不會串聯至交錯的子項資料表,因為主鍵欄無法設為NULL。只有在其他外鍵參照更新後的資料欄時,才會觸發進一步動作。ON DELETE CASCADE會刪除整個參照資料列,因此也會串連至任何具有ON DELETE CASCADE的交錯子資料表,以及下游外鍵。
強制執行外鍵和資料表交錯的比較
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 呈現更新後的資料庫結構定義,其中包含與 Orders 交錯的新資料表 OrderItems。您也可以在這裡看到這兩個資料表之間的一對多關係。
圖 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 也會驗證資料表中的現有資料,確保資料符合外鍵的參照完整性限制。如有任何資料無效,結構定義變更就會失敗。 | Spanner 會視需要回填參照的索引,且不會驗證資料表中的現有資料。 |
不支援以下項目:
- 將外鍵動作新增至現有的強制執行外鍵限制。
- 變更現有外鍵的強制執行設定。
無論是哪一種情況,都建議您改為採取下列做法:
- 新增限制,並指定必要動作或強制執行。
- 捨棄舊限制。
新增限制並捨棄舊限制,可避免長時間執行的變更限制作業問題。舉例來說,假設您想在現有的外鍵上新增 DELETE CASCADE 動作。使用 ON DELETE CASCADE 動作建立新的外鍵後,這兩項限制的效果都是 DELETE CASCADE 動作。接著,您就能放心地捨棄舊限制。
如果其他外鍵限制未使用索引,捨棄限制可能會導致捨棄外鍵支援索引。因此,如果先捨棄舊限制,之後再新增具有動作的相同外鍵限制,可能會導致長時間執行的作業,例如回填索引、驗證不重複索引限制,或驗證外鍵參照限制。
您可以查詢 INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS.SPANNER_STATE,檢查外鍵建立狀態。