このドキュメントでは、Spanner の外部キーとデータベース ソリューションでの参照完全性の適用方法について説明します。外部キーとその使用方法については、次のトピックをご覧ください。
- Spanner の外部キーの概要
- 外部キーの種類
- 外部キーの種類の比較
- 使用する外部キーの種類を選択する
- 適用された外部キーを使用する
- 情報用の外部キーを使用する
- バックアップ インデックス
- 長時間実行スキーマの変更
Spanner の外部キーの概要
外部キーはテーブル間の関係を定義します。外部キーを使用すると、Spanner 内でこれらの関係のデータの整合性が維持されます。
たとえば、e コマース ビジネスの主任開発者として顧客の注文を処理するデータベースを設計している場合について考えてみましょう。データベースには、各注文、顧客、商品に関する情報を格納します。図 1 は、アプリケーションの基本的なデータベース構造を示しています。
図 1: 注文処理データベースの図
顧客情報を格納する Customers
テーブル、すべての注文を追跡する Orders
テーブル、各商品に関する情報を格納する Products
テーブルを定義します。
図 1 は次の実世界の関係に対応するテーブル間の関連性も示しています。
顧客が注文します。
商品が発注されます。
データベースでは、次のルールを適用して、システム内の注文が有効であることを確認します。
存在しない顧客の注文は作成できない。
顧客は、取り扱いのない商品を注文できない。
これらのルール、つまり「制約」を適用すると、データの「参照整合性」が維持されます。データベースの参照整合性が維持されていれば、データ間のリンクや参照が不正となるような無効なデータを追加しようとしても失敗します。参照整合性により、ユーザーエラーを防ぐことができます。デフォルトでは、Spanner は外部キーを使用して参照整合性を適用します。
外部キーによる参照整合性を定義する
注文処理の例をもう一度見てみましょう。詳細は図 2 のようになります。
図 2. 外部キーを使用したデータベース スキーマの図
この設計では、各テーブルに列名と型が示されています。Orders
テーブルは、2 つの外部キーの関係も定義しています。FK_CustomerOrder
は、Orders
のすべての行に有効な CustomerId
があることを前提としています。FK_ProductOrder
外部キーにより、Orders
テーブルのすべての ProductId
値が有効になります。次の表に、これらの制約と適用する実際のルールの対応を示します。
外部キー名 | 制約 | 実際の内容 |
---|---|---|
FK_CustomerOrder | Orders のすべての行に有効な CustomerId がある |
有効な顧客が注文を行っている |
FK_ProductOrder | Orders のすべての行に有効な ProductId がある |
有効な商品が注文された |
Spanner は、適用された外部キーで指定されている制約を適用します。つまり、Customers
テーブルと Products
テーブルで CustomerId
または ProductId
がない Orders
テーブルに、行を挿入または更新しようとすると、Spanner は失敗します。また、Customers
テーブルと Products
テーブルの行の更新または削除により Orders
テーブルの ID が無効になるようなトランザクションも失敗します。Spanner による制約の検証方法の詳細については、以下のトランザクションの制約の検証をご覧ください。
適用される外部キーとは異なり、Spanner は情報用の外部キーの制約を検証しません。つまり、このシナリオで情報用の外部キーを使用する場合、Customers
テーブルと Products
テーブルで CustomerId
または ProductId
がない Orders
テーブルに、行を挿入または更新しようとするトランザクションは検証されず、トランザクションは失敗しません。また、適用された外部キーとは異なり、情報用の外部キーは PostgreSQL ではなく、GoogleSQL でのみサポートされています。
外部キーの特徴
Spanner の外部キーの特徴は次のとおりです。
外部キーを定義するテーブルは、参照元のテーブルで、外部キー列は参照元の列です。
外部キーは、参照先テーブルの参照先の列を参照します。
例のように、各外部キーの制約に名前を付けることができます。名前を指定しない場合、Spanner によって名前が生成されます。生成された名前は、Spanner の
INFORMATION_SCHEMA
からクエリできます。制約名は、テーブルとインデックスの名前によるスキーマの範囲に収まり、スキーマ内で一意である必要があります。参照元の列と参照先の列の数は同じでなければなりません。重要なのは順序です。たとえば、最初の参照元の列は最初の参照先の列を参照し、2 番目の参照元の列は 2 番目の参照先の列を参照します。
参照元の列と、それに対応する参照先の列は同じ型である必要があります。列のインデックス登録が可能な状態にする必要があります。
allow_commit_timestamp=true
オプションを使用して列に外部キーを作成することはできません。配列の列はサポートされていません。
JSON 列はサポートされていません。
外部キーが同じテーブルの列(自己参照外部キー)を参照することがあります。たとえば、テーブルの
EmployeeId
列を参照するManagerId
列を持つEmployee
テーブルがあります。外部キーは、2 つのテーブルが直接または間接的に相互に参照するテーブルの間で、循環関係を形成することもあります。外部キーを作成する前に、参照先のテーブルが存在している必要があります。つまり、
ALTER TABLE
ステートメントを使用して外部キーを少なくとも 1 つ追加する必要があります。参照先のキーは一意である必要があります。外部キーの参照列が参照テーブルの主キー列と一致する場合、Spanner は参照テーブルの
PRIMARY KEY
を使用します。Spanner は、参照されるテーブルの主キーを使用できない場合、参照先の列にUNIQUE NULL_FILTERED INDEX
を作成します。外部キーは、作成したセカンダリ インデックスを使用しません。独自のバックアップ インデックスを作成します。バックアップ インデックスは、明示的な
force_index
ディレクティブを含むクエリ評価で使用できます。バックアップ インデックスの名前は、Spanner のINFORMATION_SCHEMA
からクエリできます。詳細については、バックアップ インデックスをご覧ください。
外部キーの種類
外部キーには、適用と情報の 2 種類があります。適用外部キーがデフォルトで、参照整合性を強制します。情報用の外部キーは参照整合性を適用しません。これは、クエリの最適化のために意図した論理データモデルを宣言する際に最適です。詳細については、後述の適用される外部キーと情報用外部キーのセクションと、外部キーの種類の比較の表をご覧ください。
適用される外部キー
適用される外部キー(Spanner のデフォルトの外部キーの種類)は、参照整合性を適用します。適用された外部キーは参照整合性を適用するため、次の操作が失敗します。
参照元のテーブルに存在しない外部キー値を持つ参照先テーブルに行を追加すると、失敗します。
参照元テーブル内の行から参照されている参照元テーブルから行を削除すると、失敗します。
すべての PostgreSQL 外部キーが適用されます。GoogleSQL 外部キーはデフォルトで適用されます。外部キーはデフォルトで適用されるため、ENFORCED
キーワードを使用して GoogleSQL 外部キーが適用されることを指定する必要はありません。
情報用の外部キー
情報用の外部キーは、クエリの最適化のために目的の論理データモデルを宣言するために使用されます。参照先のテーブルキーは情報用の外部キーで一意である必要がありますが、参照整合性は適用されません。情報用の外部キーを使用するときに、参照整合性を部分的に検証する場合は、クライアント側で検証ロジックを管理する必要があります。詳細については、情報用の外部キーを使用するをご覧ください。
NOT ENFORCED
キーワードを使用して、GoogleSQL 外部キーが情報提供用であることを指定します。PostgreSQL は情報用の外部キーをサポートしていません。
外部キーの種類の比較
適用と情報の両方にはメリットがあります。以降のセクションでは、2 種類の外部キーを比較し、そのベスト プラクティスについて説明します。
外部キーの大まかな違い
適用と情報の外部キーの主な違いは次のとおりです。
適用。適用された外部キーは、書き込み時の参照整合性を検証して保証します。情報用の外部キーは、参照整合性を検証または保証しません。
ストレージ。適用された外部キーでは、制約付きテーブルのバックアップ インデックスに追加のストレージが必要になる場合があります。
書き込みスループット。適用された外部キーでは、情報用の外部キーよりも書き込みパスのオーバーヘッドが大きくなる可能性があります。
クエリの最適化。どちらのタイプの外部キーも、クエリの最適化に使用できます。オプティマイザーが情報用の外部キーに対応している場合、データと情報用の外部キーとの関係が一致しない場合(制約付きの一部のキーに、参照先テーブルに一致する参照キーがない)など、クエリ結果に実際のデータが反映されないことがあります。
外部キーの違いを示す表
次の表に、適用される外部キーと情報用の外部キーの詳細な違いを示します。
適用される外部キー | 情報用の外部キー | |
---|---|---|
キーワード | ENFORCED |
NOT ENFORCED |
GoogleSQL によるサポート | はい。GoogleSQL の外部キーはデフォルトで適用されます。 | はい。 |
PostgreSQL でのサポート | はい。PostgreSQL の外部キーは適用のみ可能です。 | いいえ。 |
ストレージ | 適用された外部キーには、最大 2 つのバックアップ インデックスのストレージが必要です。 | 情報用の外部キーには、最大 1 つのバックアップ インデックスのストレージが必要です。 |
参照先のテーブル列にバッキング インデックスを必要に応じて作成します。 | はい。 | はい。 |
必要に応じて、参照元のテーブル列にバックアップ インデックスを作成します。 | はい。 | いいえ。 |
外部キーのアクションのサポート | はい。 | いいえ。 |
参照整合性を検証して適用する | はい。 | いいえ。検証を行わないと書き込みパフォーマンスが向上しますが、情報用の外部キーがクエリの最適化に使用されている場合は、クエリ結果に影響する可能性があります。参照整合性を確保するには、クライアントサイドでの検証または適用された外部キーを使用できます。 |
使用する外部キーの種類を選択する
使用する外部キーの種類を決定するには、次のガイドラインを使用します。
適用された外部キーから始めることをおすすめします。適用された外部キーにより、データと論理モデルの整合性が常に維持されます。適用された外部キーは、ユースケースで機能しない場合を除き、推奨のオプションです。
次の条件をすべて満たす場合は、情報用の外部キーの使用を検討することをおすすめします。
クエリの最適化で、情報用の外部キーで記述された論理データモデルを使用したい。
厳格な参照整合性を維持することは非現実的であるか、パフォーマンスに大きな影響を与える情報用の外部キーを使用する必要がある場合の例を以下に示します。
アップストリーム データソースが結果整合性モデルに従っている。この場合、ソースシステムで行われた更新が Spanner にすぐに反映されないことがあります。更新がすぐに行われない可能性があるため、外部キーの関係で一時的な不整合が発生することがあります。
データに、参照関係が多数ある参照行が含まれています。これらの行の更新では、参照整合性の維持に関連するすべての行を検証する必要があるため、また場合によっては削除も必要になるため、多くのリソースが使用される可能性があります。このシナリオでは、更新が Spanner のパフォーマンスに影響し、同時実行トランザクションが遅くなる可能性があります。
アプリケーションは、潜在的なデータの不整合と、それらがクエリ結果に与える影響を処理できます。
情報用の外部キーを使用する
以下のトピックは、情報用の外部キーに関するものです。情報用と適用された外部キーの両方に適用されるトピックについては、以下をご覧ください。
情報用の外部キーを使用して新しいテーブルを作成する
Spanner データベースに情報用の外部キーを作成したり、削除するには、DDL ステートメントを使用します。外部キーは 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
アクションでは、参照先の外部キーを含む行を削除すると、そのキーを参照するすべての行も同じトランザクションで削除されます。
外部キーは、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 は、トランザクションが commit されたとき、またはトランザクションの後続の操作で書き込みの効果が参照可能になったときに、適用された外部キーの制約を検証します。
参照元の列に挿入された値は、参照先のテーブルと参照先の列の値と照合されます。参照元の値が NULL
の行は確認されません。つまり、参照元テーブルに追加されます。
Spanner は、DML ステートメントまたは API を介してデータを更新しようとするときに、該当するすべての適用外部キーの参照制約を検証します。制約が無効な場合、保留中の変更はすべてロールバックされます。
各 DML ステートメントの直後に検証が行われます。たとえば、参照元の行を挿入する前に、参照先の行を挿入する必要があります。Mutation API を使用する場合、トランザクションが commit されるまでミューテーションがバッファリングされます。外部キーの検証は、トランザクションが commit されるまで延期されます。この場合、最初に参照元の行を挿入できます。
各トランザクションは、外部キー制約に影響する変更について評価されます。これらの評価では、サーバーへの追加リクエストが必要になる場合があります。バックアップ インデックスでは、トランザクションの変更を評価してインデックスを維持するための追加の処理時間も必要です。インデックスごとに追加のストレージも必要です。
長時間実行の削除カスケード アクション
参照元のテーブルから行を削除した場合、Spanner は削除された行を参照する参照元テーブル内のすべての行を削除する必要があります。そのため、1 つの削除オペレーションで他の数千の削除オペレーションが発生する可能性があります。削除カスケードのアクションを含む外部キー制約をテーブルに追加するか、削除カスケードのアクションがある外部キー制約を含むテーブルを作成すると、削除オペレーションが遅くなる可能性があります。
外部キーの削除カスケードのミューテーションの上限を超えた
外部キーの削除カスケードを使用して大量のレコードを削除すると、パフォーマンスに影響する可能性があります。これは、削除された各レコードが、それに関連するすべてのレコードの削除を呼び出すためです。外部キー削除カスケードを使用して大量のレコードを削除する必要がある場合は、親テーブルから行を削除する前に、子テーブルから行を明示的に削除します。これにより、ミューテーションの制限によるトランザクションの失敗がなくなります。
適用された外部キーとテーブルのインターリーブの比較
子テーブルの主キーに親テーブルの主キー列が含まれる親子関係で、多くの作業がある場合は、Spanner のテーブル インターリーブが適しています。子行と親行を同じ場所に配置することで、パフォーマンスが大幅に向上します。
外部キーはより一般的な親子ソリューションであり、その他のユースケースに対応します。主キー列に制限されることなく、テーブルに複数の外部キー関係(ある関係では親として、その他の関係では子として)を持たせることもできます。ただし、外部キー関係は、ストレージ レイヤ内でのテーブルのコロケーションを示唆するわけではありません。
次のように定義された Orders
テーブルを使用する例について考えてみましょう。
図 3.適用された外部キーを含むデータベース スキーマの図
図 3 の設計にはいくつかの制限があります。たとえば、各注文に含めることができる注文アイテムは 1 つのみです。
注文ごとに複数の商品を注文できるようにしたいという顧客も存在するはずです。注文した各商品のエントリを含む 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
でインターリーブした結果として更新されたデータベース スキーマを視覚的に表したものです。これらの 2 つのテーブル間の 1 対多の関係も表示されます。
図 4. インターリーブされた OrderItems テーブルの追加
この構成では、各注文に複数の OrderItems
エントリを含めることができ、各注文の OrderItems
エントリがインターリーブされ、注文と同じ場所に配置されます。この方法で Orders
と OrderItems
を物理的にインターリーブすることで、テーブルを効果的に事前結合し、関連する行に同時にアクセスしてディスク アクセスを最小限に抑え、パフォーマンスを向上させることが可能です。たとえば、Spanner はローカルで主キーによる結合を実行し、ディスク アクセスとネットワーク トラフィックを最小限に抑えることができます。
トランザクションでミューテーションの数が 80,000 を超えると、そのトランザクションは失敗します。このような大規模なカスケード削除は、「親でインターリーブされる」関係のテーブルには機能しますが、外部キー関係を持つテーブルには機能しません。外部キー関係があり、大量の行を削除する必要がある場合は、まず子テーブルから行を明示的に削除する必要があります。
ユーザー テーブルが別のテーブルと外部キー関係があり、参照先のテーブルから行を削除すると、何百万もの行が削除される場合、「親でインターリーブされる」削除カスケード アクションでスキーマを設計する必要があります。
比較表
次の表は、外部キーとテーブル インターリーブの比較をまとめたものです。この情報を使用して、設計に適したものを判断してください。
親子関係のタイプ | テーブル インターリーブ | 適用される外部キー |
---|---|---|
主キーを使用できる | はい | はい |
主キー以外の列を使用できる | いいえ | はい |
サポートされている親の数 | 0 .. 1 | 0 .. N |
親データと子データを一緒に格納する | はい | いいえ |
カスケード削除をサポート | はい | はい |
Null マッチング モード | 参照元の値と参照先の値が異なる場合に渡されます。 Null 値と null 値の区別はありません。null 値と非 null 値は区別されます。 |
参照元の値が null の場合は渡されます。 参照元のすべての値が非 null で、参照先のテーブルに参照元の値と同じ値の行がある場合に渡されます。 一致する行が見つからないと失敗します。 |
適用のタイミング | mutation API を使用する場合はオペレーションごと。 DML を使用する場合はステートメントごと。 |
mutation API を使用する場合はトランザクションごと。 DML を使用する場合はステートメントごと。 |
削除が可能 | いいえ。テーブル インターリーブは、子テーブル全体を削除しない限り、作成後に削除できません。 | はい |
バックアップ インデックス
外部キーはユーザーが作成したインデックスを使用しません。独自のバックアップ インデックスを作成します。適用される外部キーと情報用の外部キーでは、Spanner でバックアップ インデックスが異なる方法で作成されます。
適用される外部キーの場合、Spanner は外部キーごとに 2 つのセカンダリ バックアップ インデックスを作成できます。一方は参照元の列、もう一方は参照先の列です。
情報用の外部キーの場合、Spanner は参照先の列に必要に応じて最大 1 つのバックアップ インデックスを作成できます。情報用の外部キーでは、参照元の列のバックアップ インデックスは作成されません。
適用される外部キーと情報用の外部キーの両方の場合、通常、外部キーは参照先テーブルの主キーを参照するため、参照先テーブルのインデックスは不要です。このため、情報用の外部キーには通常、バックアップ インデックスが設定されません。必要な場合に参照先のテーブルに作成されるバックアップ インデックスは UNIQUE NULL_FILTERED
インデックスです。既存のデータがインデックスの一意性の制約に違反している場合、外部キーの作成は失敗します。
情報用の外部キーには、参照元テーブルのバックアップ インデックスがありません。適用される外部キーの場合、参照元テーブルのバックアップ インデックスは NULL_FILTERED
です。
複数の外部キーが同じバックアップ インデックスを必要とする場合、Spanner はそれぞれに 1 つのインデックスを作成します。バックアップ インデックスは、それらを使用する外部キーが破棄されると破棄されます。ユーザーがバックアップ インデックスを変更または破棄することはできません。
Spanner は、各データベースの情報スキーマを使用して、バックアップ インデックスに関するメタデータを格納します。SPANNER_IS_MANAGED
値が true
の INFORMATION_SCHEMA.INDEXES
内の行は、バックアップ インデックスを表します。
情報スキーマを直接呼び出す SQL クエリを除き、Google Cloud コンソールにはデータベースのバックアップ インデックスに関する情報は表示されません。
長時間実行スキーマの変更
既存のテーブルに外部キーを追加するか、外部キーを使用して新しいテーブルを作成すると、長時間実行オペレーションが発生する可能性があります。新しいテーブルの場合、長時間実行オペレーションが完了するまでテーブルに書き込みはできません。
次の表に、適用された外部キーと情報用の外部キーが新しいテーブルまたは既存のテーブルにある場合に Spanner で発生する処理を示します。
テーブルタイプ | 適用される外部キー | 情報用の外部キー |
---|---|---|
新規 | Spanner は、外部キーごとに必要に応じて参照先インデックスをバックフィルします。 | Spanner は、外部キーごとに必要に応じて参照先インデックスをバックフィルします。 |
既存 | Spanner は、必要に応じて参照元インデックスと参照先インデックスをバックフィルします。また、Spanner はテーブルの既存のデータを検証して、外部キーの参照整合性制約に準拠していることを確認します。無効なデータがあると、スキーマの変更は失敗します。 | Spanner は必要に応じて参照先インデックスをバックフィルし、テーブル内の既存のデータを検証しません。 |
以下のことはサポートされていません。
- 既存の適用済みの外部キー制約に外部キーのアクションを追加する。
- 既存の外部キーの適用を変更する。
どちらの場合も、代わりに次のことをおすすめします。
- 必要なアクションまたは適用を伴う新しい制約を追加する。
- 古い制約を削除する。
新しい制約を追加して古い制約を削除すると、長時間実行される Alter 制約オペレーションの問題を防ぐことができます。たとえば、既存の外部キーに DELETE CASCADE
アクションを追加するとします。ON DELETE CASCADE
アクションを使用して新しい外部キーを作成すると、両方の制約の効果は DELETE CASCADE
アクションになります。その後、古い制約を安全に削除できます。
制約を破棄すると、外部キーのバックアップ インデックスが破棄される可能性があります(他の外部キー制約でインデックスが使用されていない場合)。このため、最初に古い制約を削除してから、後でアクションを使用して同じ外部キー制約を追加すると、インデックスのバックフィル、一意のインデックス制約の検証、外部キー参照制約の検証など、長時間実行オペレーションが発生する可能性があります。
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS.SPANNER_STATE
にクエリを実行して、外部キーの作成状態を確認できます。
次のステップ
外部キー関係の作成と管理について学習する。
情報スキーマについて学習する。