Informationen zu Schemas

Auf dieser Seite werden Schemas erläutert und verschachtelte Tabellen vorgestellt, die die Abfrageleistung beim Abfragen von Tabellen in einer hierarchischen Beziehung verbessern können.

Cloud Spanner-Datenbanken enthalten eine oder mehrere Tabellen. Tabellen sind als Zeilen und Spalten strukturiert. Eine oder mehrere Spalten sind als Primärschlüssel der Tabelle definiert, der jede Zeile eindeutig identifiziert. Primärschlüssel werden immer indexiert, um eine schnelle Zeilensuche zu ermöglichen. Sie können sekundäre Indexe für eine oder mehrere Spalten definieren. Wenn Sie vorhandene Zeilen in einer Tabelle aktualisieren oder löschen möchten, muss die Tabelle einen Primärschlüssel haben. Eine Tabelle ohne Primärschlüsselspalten kann nur eine Zeile haben. Nur GoogleSQL-Dialekt-Datenbanken können Tabellen ohne Primärschlüssel haben.

Daten in Spanner sind stark typisiert. Sie müssen für jede Datenbank ein Schema definieren, das den Datentyp jeder Spalte jeder Tabelle angeben muss. Zu den Datentypen gehören skalare und komplexe Typen, die unter Datentypen in GoogleSQL und PostgreSQL-Datentypen beschrieben werden.

Hierarchische Tabellenbeziehungen

Es gibt zwei Möglichkeiten, hierarchische Beziehungen in Spanner zu definieren: Tabellenverschachtelung und Fremdschlüssel.

Die Tabellenverschachtelung von Spanner ist eine gute Wahl für viele hierarchische Beziehungen. Bei der Verschränkung platziert Spanner untergeordnete Zeilen physisch gemeinsam mit übergeordneten Zeilen im Speicher. Eine gemeinsame Standortbestimmung kann die Leistung erheblich verbessern. Wenn Sie beispielsweise eine Customers-Tabelle und eine Invoices-Tabelle haben und Ihre Anwendung häufig alle Rechnungen für einen Kunden abruft, können Sie Invoices als verschränkte untergeordnete Tabelle von Customers definieren. Dazu deklarieren Sie eine Datenlokalitätsbeziehung zwischen zwei unabhängigen Tabellen. Sie weisen Spanner an, eine oder mehrere Zeilen von Invoices mit einer Customers-Zeile zu speichern.

Sie verknüpfen eine untergeordnete Tabelle mithilfe von DDL mit einer übergeordneten Tabelle, die die untergeordnete Tabelle als mit der übergeordneten Tabelle verschränkt deklariert. Außerdem verwenden Sie den Primärschlüssel der übergeordneten Tabelle als ersten Teil des zusammengesetzten Primärschlüssels der untergeordneten Tabelle. Weitere Informationen zur Verschränkung finden Sie weiter unten in diesem Thema unter Verschränkte Tabellen erstellen.

Fremdschlüssel sind eine allgemeinere über-/untergeordnete Lösung, die zusätzliche Anwendungsfälle behandelt. Sie sind nicht auf Primärschlüsselspalten beschränkt und Tabellen können mehrere Fremdschlüsselbeziehungen haben, die in einigen Beziehungen als übergeordnete und in anderen als untergeordnete Beziehungen gelten. Eine Fremdschlüsselbeziehung impliziert jedoch nicht, dass sich die Tabellen auf der Speicherebene befinden.

Google empfiehlt, dass Sie hierarchische Beziehungen entweder als verschränkte Tabellen oder als Fremdschlüssel darstellen, aber nicht beides. Weitere Informationen zu Fremdschlüsseln und ihrem Vergleich mit verschränkten Tabellen finden Sie in der Übersicht über Fremdschlüssel.

Primärschlüssel auswählen

Oft hat Ihre Anwendung bereits ein Feld, das als Primärschlüssel verwendet werden kann. Für eine Customers-Tabelle kann es beispielsweise einen von der Anwendung bereitgestellten CustomerId geben, der sich gut als Primärschlüssel eignet. In anderen Fällen müssen Sie beim Einfügen der Zeile möglicherweise einen Primärschlüssel generieren. Dies ist in der Regel ein eindeutiger Ganzzahlwert ohne geschäftliche Bedeutung (ein Ersatz-Primärschlüssel).

In allen Fällen sollten Sie darauf achten, keine Hotspots mit der Wahl Ihres Primärschlüssels zu erstellen. Wenn Sie beispielsweise Datensätze mit einer monoton ansteigenden Ganzzahl als Schlüssel einfügen, fügen Sie sie immer am Ende des Schlüsselbereichs ein. Dies ist nicht wünschenswert, da Spanner die Daten nach Schlüsselbereichen auf die Server teilt. Das bedeutet, dass Ihre Einfügungen an einen einzelnen Server gerichtet werden und einen Hotspot erzeugen. Mit diesen Verfahren können Sie die Last auf mehrere Server verteilen und Hotspots vermeiden:

Sekundäre Indexe basierend auf Primärschlüsseln hinzufügen

Unter bestimmten Umständen kann die Datenbanknutzung vom Hinzufügen von sekundären Indexen auf Basis von Primärschlüsseln profitieren. Dies gilt insbesondere, wenn Sie häufig Abfragen ausführen, die Scans in umgekehrter Reihenfolge des Primärschlüssels einer Tabelle erfordern.

Primärschlüssel in verschränkten Tabellen

Bei der Verschränkung muss jede Tabelle einen Primärschlüssel haben. Wenn Sie eine Tabelle als verschränkte untergeordnete Tabelle einer anderen Tabelle deklarieren, muss die Tabelle einen zusammengesetzten Primärschlüssel haben, der alle Komponenten des Primärschlüssels der übergeordneten Tabelle in derselben Reihenfolge und in der Regel eine oder mehrere zusätzliche untergeordnete Tabellenspalten enthält.

Spanner speichert Zeilen in sortierter Reihenfolge nach Primärschlüsselwerten, wobei untergeordnete Zeilen zwischen übergeordneten Zeilen eingefügt werden. Eine Abbildung verschränkter Zeilen finden Sie weiter unten im Abschnitt Verschränkte Tabellen erstellen.

Zusammenfassung: Spanner kann Zeilen zusammengehöriger Tabellen an einem Ort speichern. Die Schemabeispiele zeigen, wie dieses physische Layout aussieht.

Datenbankaufteilungen

Sie können Hierarchien von verschachtelten hierarchischen Beziehungen mit bis zu sieben Ebenen definieren. Dies bedeutet, dass Sie Zeilen von sieben unabhängigen Tabellen gemeinsam unterbringen können. Wenn die Daten in den Tabellen klein sind, kann die Datenbank wahrscheinlich von einem einzelnen Spanner-Server verarbeitet werden. Aber was passiert, wenn Ihre relationalen Tabellen wachsen und die Ressourcengrenzen eines einzelnen Servers erreichen? Spanner ist eine verteilte Datenbank, d. h., wenn eine Datenbank wächst, teilt Spanner Ihre Daten in Portionen auf, die als "Splits" bezeichnet werden. Splits können unabhängig voneinander verschoben und verschiedenen Servern zugewiesen werden, die sich an verschiedenen physischen Standorten befinden können. Ein Split enthält einen Bereich von zusammenhängenden Zeilen. Die Start- und Endschlüssel dieses Bereichs werden als "Split-Grenzen" bezeichnet. Spanner fügt automatisch Split-Grenzen anhand von Größe und Last hinzu und entfernt sie. Dadurch ändert sich die Anzahl der Splits in der Datenbank.

Lastbasierte Aufteilung

Ein Beispiel dafür, wie Spanner eine lastbasierte Aufteilung durchführt, um Leseschwerpunkte abzumildern, nehmen wir an, dass Ihre Datenbank eine Tabelle mit 10 Zeilen enthält, die häufiger gelesen werden als alle anderen Zeilen in der Tabelle. Spanner kann Split-Grenzen zwischen jeder dieser zehn Zeilen hinzufügen, sodass sie jeweils von einem anderen Server verarbeitet werden, anstatt zuzulassen, dass alle Lesevorgänge dieser Zeilen die Ressourcen eines einzelnen Servers verbrauchen.

Wenn Sie sich an die Best Practices für das Schemadesign halten, kann Spanner Hotspots so abschwächen, dass der Lesedurchsatz alle paar Minuten verbessert wird, bis die Ressourcen in Ihrer Instanz ausgelastet sind oder wenn keine neuen Split-Grenzen hinzugefügt werden können (da Sie einen Split haben, der nur eine einzelne Zeile ohne verschränkte untergeordnete Elemente abdeckt).

Schemabeispiele

Die folgenden Schemabeispiele zeigen, wie übergeordnete und untergeordnete Tabellen mit und ohne Verschränkung erstellt werden. Außerdem werden die entsprechenden physischen Layouts der Daten veranschaulicht.

Übergeordnete Tabelle erstellen

Angenommen, Sie erstellen eine Musikanwendung und Sie benötigen eine einfache Tabelle, in der Zeilen von Sängerdaten gespeichert werden:

Tabelle "Singers" mit 5 Zeilen und 4 Spalten „SingerID“ ist die erste Spalte.

Beachten Sie, dass die Tabelle eine Primärschlüsselspalte SingerId enthält, die links neben der fett gedruckten Linie angezeigt wird, und dass die Tabellen nach Zeilen und Spalten organisiert sind.

Sie können die Tabelle mit einem Spanner-Schema so definieren:

GoogleSQL

CREATE TABLE Singers (
SingerId   INT64 NOT NULL,
FirstName  STRING(1024),
LastName   STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

Beachten Sie Folgendes zum Beispielschema:

  • Singers ist eine Tabelle auf der Stammebene der Datenbankhierarchie (da sie nicht als verschachteltes untergeordnetes Element einer anderen Tabelle definiert ist).
  • Bei GoogleSQL-Dialektdatenbanken werden Primärschlüsselspalten normalerweise mit NOT NULL annotiert. Sie können diese Annotation jedoch auslassen, wenn Sie NULL-Werte in Schlüsselspalten zulassen möchten. Weitere Informationen finden Sie unter Schlüsselspalten.
  • Nicht im Primärschlüssel enthaltene Spalten werden als Nicht-Schlüsselspalten bezeichnet und können die optionale Annotation NOT NULL enthalten.
  • Spalten, die in GoogleSQL den Typ STRING oder BYTES verwenden, müssen mit einer Länge definiert werden, die die maximale Anzahl von Unicode-Zeichen angibt, die im Feld gespeichert werden können. Die Längenangabe ist für die PostgreSQL-Typen varchar und character varying optional. Weitere Informationen finden Sie unter Skalare Datentypen für GoogleSQL-Dialekt-Datenbanken und PostgreSQL-Datentypen für PostgreSQL-Dialekt-Datenbanken.

Wie sieht das physische Layout der Zeilen in der Tabelle Singers aus? Das folgende Diagramm zeigt Zeilen der Tabelle Singers, die nach Primärschlüsseln gespeichert sind ("Sänger(1)", dann "Sänger(2)" usw., wobei die Zahl in Klammern der Primärschlüsselwert ist.

Beispielzeilen einer Tabelle, die in der Reihenfolge des Primärschlüssels gespeichert sind. Eine gestrichelte Linie zeigt eine Split-Grenze zwischen den Schlüsseln 3 und 4 an.

Das obige Diagramm zeigt eine beispielhafte Split-Grenze zwischen den Zeilen mit den Schlüsseln Singers(3) und Singers(4), wobei die Daten aus den resultierenden Splits verschiedenen Servern zugewiesen werden. Wenn diese Tabelle größer wird, können Zeilen mit Singers-Daten an verschiedenen Orten gespeichert sein.

Übergeordnete und untergeordnete Tabellen erstellen

Angenommen, Sie möchten nun einige grundlegende Daten über die Alben jedes Sängers zur Musikanwendung hinzufügen.

Albumtabelle mit 5 Zeilen und 3 Spalten. Die Primärschlüsselspalten befinden sich links.

Beachten Sie, dass der Primärschlüssel von Albums aus zwei Spalten besteht: SingerId und AlbumId, um jedes Album mit seinem Sänger zu verknüpfen. Im folgenden Beispielschema werden sowohl die Albums- als auch die Singers-Tabelle am Stamm der Datenbankhierarchie definiert. Damit sind sie gleichgeordnete Tabellen.

-- Schema hierarchy:
-- + Singers (sibling table of Albums)
-- + Albums (sibling table of Singers)

GoogleSQL

CREATE TABLE Singers (
 SingerId   INT64 NOT NULL,
 FirstName  STRING(1024),
 LastName   STRING(1024),
 SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
SingerId     INT64 NOT NULL,
AlbumId      INT64 NOT NULL,
AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

CREATE TABLE albums (
singer_id     BIGINT,
album_id      BIGINT,
album_title   VARCHAR,
PRIMARY KEY (singer_id, album_id)
);

Das physische Layout der Zeilen von Singers und Albums sieht wie im folgenden Diagramm aus. Die Zeilen der Tabelle Albums sind nach zusammenhängenden Primärschlüsseln gespeichert. Danach sind die Zeilen der Tabelle Singers nach zusammenhängenden Primärschlüsseln gespeichert:

Physisches Layout der Zeilen Primärschlüssel werden in der Spalte ganz links angezeigt.
    Beispiel: Alben(2;1), Albums(2;2) usw.

Ein wichtiger Hinweis zu dem Schema ist, dass Spanner keine Datenlokalitätsbeziehungen zwischen den Tabellen Singers und Albums annimmt, da es sich um übergeordnete Tabellen handelt. Wenn die Datenbank wächst, kann Spanner Split-Grenzen zwischen den Zeilen hinzufügen. Dies bedeutet, dass sich die Zeilen der Tabelle Albums am Ende in einem anderen Split als die Zeilen der Tabelle Singers befinden können und die beiden Splits sich unabhängig voneinander verschieben können.

Je nach den Anforderungen Ihrer Anwendung kann es sinnvoll sein, dass Albums-Daten auf verschiedenen Splits von Singers-Daten gespeichert werden. Dies kann jedoch zu Leistungseinbußen führen, da Lesevorgänge und Aktualisierungen über verschiedene Ressourcen hinweg koordiniert werden müssen. Wenn Ihre Anwendung häufig Informationen zu allen Alben eines bestimmten Sängers abrufen muss, sollten Sie Albums als verschränkte untergeordnete Tabelle von Singers erstellen, in der Zeilen aus den beiden Tabellen entlang der Primärschlüsseldimension gemeinsam angeordnet sind. Im nächsten Beispiel wird dies genauer erläutert.

Verschränkte Tabellen erstellen

Eine verschränkte Tabelle ist eine Tabelle, die Sie als verschränkte untergeordnete Tabelle einer anderen Tabelle deklarieren, weil die Zeilen der untergeordneten Tabelle physisch mit der zugehörigen übergeordneten Zeile gespeichert werden sollen. Wie bereits erwähnt, muss der Primärschlüssel der übergeordneten Tabelle der erste Teil des zusammengesetzten Primärschlüssels der untergeordneten Tabelle sein.

Angenommen, Sie entwickeln Ihre Musikanwendung und stellen fest, dass die App häufig auf Zeilen aus der Tabelle Albums zugreifen muss, wenn sie auf eine Zeile vom Typ Singers zugreift. Wenn Sie beispielsweise auf die Zeile Singers(1) zugreifen, müssen Sie auch auf die Zeilen Albums(1, 1) und Albums(1, 2) zugreifen. In diesem Fall benötigen Singers und Albums eine starke Datenlokalitätsbeziehung. Sie können diese Datenlokalitätsbeziehung durch Erstellen von Albums als verschränkte untergeordnete Tabelle von Singers angeben.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)

Die fett gedruckte Zeile im folgenden Schema zeigt, wie Sie Albums als verschränkte Tabelle von Singers erstellen.

GoogleSQL

CREATE TABLE Singers (
 SingerId   INT64 NOT NULL,
 FirstName  STRING(1024),
 LastName   STRING(1024),
 SingerInfo BYTES(MAX),
 ) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 AlbumTitle   STRING(MAX),
 ) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

Hinweise zu diesem Schema:

  • SingerId, der der erste Teil des Primärschlüssels der untergeordneten Tabelle Albums ist, ist auch der Primärschlüssel der entsprechenden übergeordneten Tabelle Singers.
  • Die Annotation ON DELETE CASCADE bedeutet, dass beim Löschen einer Zeile der übergeordneten Tabelle auch die ihr untergeordneten Zeilen automatisch gelöscht werden. Wenn eine untergeordnete Tabelle diese Annotation nicht hat oder die Annotation ON DELETE NO ACTION ist, müssen Sie die untergeordneten Zeilen löschen, bevor Sie die übergeordnete Zeile löschen können.
  • Verschränkte Zeilen werden zuerst nach Zeilen der übergeordneten Tabelle und dann nach zusammenhängenden Zeilen der untergeordneten Tabelle sortiert, die den Primärschlüssel der übergeordneten Tabelle teilen. Zum Beispiel: "Singers(1)", dann "Albums(1, 1)", dann "Albums(1, 2)" und so weiter.
  • Die Datenlokalitätsbeziehung zwischen jedem Sänger und seinen Albumdaten wird beim Aufteilen dieser Datenbank beibehalten, vorausgesetzt, die Größe einer Singers-Zeile und aller zugehörigen Albums-Zeilen bleiben unter der Split-Größenbeschränkung und es gibt keinen Hotspot in diesen Albums-Zeilen.
  • Nur wenn eine übergeordnete Zeile existiert, können Sie untergeordnete Zeilen einfügen. Die übergeordnete Zeile kann entweder bereits in der Datenbank vorhanden sein oder vor der Einfügen der untergeordneten Zeilen in derselben Transaktion eingefügt werden.

Physisches Layout von Zeilen: "Albums"-Zeilen sind zwischen "Singers"-Zeilen verschränkt

Hierarchie von verschränkten Tabellen erstellen

Die hierarchische Beziehung zwischen Singers und Albums kann auf weitere nachfolgende Tabellen erweitert werden. Beispielsweise können Sie eine verschränkte Tabelle namens Songs als untergeordnetes Element von Albums erstellen, um die Trackliste jedes Albums zu speichern:

Tabelle „Songs“ mit 6 Zeilen und 4 Spalten Die drei Spalten ganz links
enthalten den Primärschlüssel.

Songs muss einen Primärschlüssel haben, der alle Primärschlüssel der in der Hierarchie übergeordneten Tabellen enthält, also SingerId und AlbumId.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
--     + Songs (interleaved table, child table of Albums)

GoogleSQL

CREATE TABLE Singers (
 SingerId   INT64 NOT NULL,
 FirstName  STRING(1024),
 LastName   STRING(1024),
 SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
 INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE TABLE Songs (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 TrackId      INT64 NOT NULL,
 SongName     STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId, TrackId),
 INTERLEAVE IN PARENT Albums ON DELETE CASCADE;

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

CREATE TABLE songs (
 singer_id     BIGINT,
 album_id      BIGINT,
 track_id      BIGINT,
 song_name     VARCHAR,
 PRIMARY KEY (singer_id, album_id, track_id)
 )
 INTERLEAVE IN PARENT albums ON DELETE CASCADE;

Das folgende Diagramm zeigt eine physische Ansicht der verschränkten Zeilen.

Physische Ansicht der Zeilen: "Songs" sind in "Albums" verschränkt und "Albums" sind zwischen "Singers" verschränkt

In diesem Beispiel fügt Spanner bei steigender Anzahl der Sänger Split-Grenzen zwischen den Sängern hinzu, um die Datenlokalität zwischen einem Sänger und seinen Album- und Songdaten aufrechtzuerhalten. Wenn jedoch die Größe einer Singer-Zeile und ihrer untergeordneten Zeilen die Split-Größenbeschränkung überschreitet oder ein Hotspot in den untergeordneten Zeilen erkannt wird, versucht Spanner, Split-Grenzen hinzuzufügen, um diese Hotspot-Zeile zusammen mit allen untergeordneten Zeilen zu isolieren.

Zusammenfassung: Eine übergeordnete Tabelle bildet zusammen mit allen untergeordneten und nachfolgenden Tabellen im Schema eine Tabellenhierarchie. Obwohl jede Tabelle in der Hierarchie logisch unabhängig ist, kann durch die physische Verschränkung die Leistung verbessert werden, da die Tabellen vorab verknüpft werden. So können Sie zusammen auf zusammengehörige Zeilen zugreifen und gleichzeitig den Speicherzugriff minimieren.

Joins mit verschränkten Tabellen

Verbinden Sie nach Möglichkeit Daten in verschränkten Tabellen mit dem Primärschlüssel. Da jede verschränkte Zeile in der Regel physisch im selben Split wie die übergeordnete Zeile gespeichert wird, kann Spanner Joins nach Primärschlüssel lokal ausführen und so den Speicherzugriff und den Netzwerk-Traffic minimieren. Im folgenden Beispiel werden Singers und Albums zum Primärschlüssel SingerId zusammengeführt.

GoogleSQL

SELECT s.FirstName, a.AlbumTitle
FROM Singers AS s JOIN Albums AS a ON s.SingerId = a.SingerId;

PostgreSQL

SELECT s.first_name, a.album_title
FROM singers AS s JOIN albums AS a ON s.singer_id = a.singer_id;

Schlüsselspalten

Dieser Abschnitt enthält einige Hinweise zu Schlüsselspalten.

Tabellenschlüssel ändern

An den Schlüsseln einer Tabelle sind keine Änderungen möglich: Sie können weder eine Schlüsselspalte zu einer vorhandenen Tabelle hinzufügen noch eine Schlüsselspalte aus einer vorhandenen Tabelle entfernen.

NULL-Werte in einem Primärschlüssel speichern

Wenn Sie in GoogleSQL NULL in einer Primärschlüsselspalte speichern möchten, lassen Sie die NOT NULL-Klausel für diese Spalte im Schema weg. (PostgreSQL-Datenbanken unterstützen keine NULL-Werte in einer Primärschlüsselspalte.)

Das folgende Beispiel zeigt das Weglassen der NOT NULL-Klausel in der Primärschlüsselspalte SingerId. Da SingerId der Primärschlüssel ist, kann es nur eine Zeile geben, in der NULL in dieser Spalte gespeichert ist.

CREATE TABLE Singers (
  SingerId   INT64,
  FirstName  STRING(1024),
  LastName   STRING(1024),
) PRIMARY KEY (SingerId);

Die Eigenschaft der Primärschlüsselspalte, für die Nullwerte zulässig sind, muss zwischen der übergeordneten und der untergeordneten Tabellendeklaration übereinstimmen. In diesem Beispiel ist NOT NULL für die Spalte Albums.SingerId nicht zulässig, da sie in Singers.SingerId weggelassen wird.

CREATE TABLE Singers (
  SingerId   INT64,
  FirstName  STRING(1024),
  LastName   STRING(1024),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Unzulässige Typen

Die folgenden Spalten dürfen nicht vom Typ ARRAY sein:

  • Die Schlüsselspalten einer Tabelle
  • Die Schlüsselspalten eines Index

Mehrmandantenfähigkeit im Blick behalten

Sie können die Mehrmandantenfähigkeit beispielsweise implementieren, wenn Sie Daten speichern, die verschiedenen Kunden gehören. Beispielsweise könnte ein Musikdienst den Inhalt jeder einzelnen Plattenfirma separat speichern wollen.

Klassische Mehrinstanzenfähigkeit

Der gängige Ansatz, für Mehrinstanzenfähigkeit zu sorgen, besteht darin, für jeden Kunden eine eigene Datenbank zu erstellen. In diesem Beispiel hat jede Datenbank ihre eigene Tabelle Singers:

Datenbank 1: Ackworth Records
SingerId FirstName LastName
1MarcRichards
2CatalinaSmith
Datenbank 2: Cama Records
SingerId FirstName LastName
1AliceTrentor
2GabrielWright
Datenbank 3: Eagan Records
SingerId FirstName LastName
1BenjaminMartinez
2HannaHarris

Schemaverwaltete Mehrmandantenfähigkeit

Eine weitere Möglichkeit für die Mehrmandantenfähigkeit in Spanner besteht darin, alle Kunden in einer einzigen Tabelle in einer einzigen Datenbank zu speichern und für jeden Kunden einen anderen Primärschlüsselwert zu verwenden. Sie können beispielsweise eine CustomerId-Schlüsselspalte in Ihre Tabellen aufnehmen. Wenn Sie CustomerId zur ersten Schlüsselspalte erklären, ist die Lokalität der Daten für jeden Kunden passend. Spanner kann dann Datenbank-Splits effektiv nutzen, um die Leistung basierend auf Datengröße und Lademustern zu maximieren. Im folgenden Beispiel gibt es eine einzige Singers-Tabelle für alle Kunden:

Spanner-Datenbank mit Mehrmandantenfähigkeit
CustomerId SingerId FirstName LastName
11MarcRichards
12CatalinaSmith
21AliceTrentor
22GabrielWright
31BenjaminMartinez
32HannaHarris

Wenn für jeden Kunden eine separate Datenbank erforderlich ist, sind diese Einschränkungen zu beachten:

  • Es gelten Limits für die Anzahl der Datenbanken pro Instanz und die Anzahl der Tabellen und Indexe pro Datenbank. Je nach Anzahl der Kunden ist es möglicherweise nicht möglich, separate Datenbanken oder Tabellen zu verwenden.
  • Das Hinzufügen neuer Tabellen und nicht verschränkter Indexe kann sehr lange dauern. Wenn Ihre Schemas so gestaltet sind, dass das Hinzufügen neuer Tabellen und Indexe erforderlich ist, können Sie möglicherweise nicht die gewünschte Leistung erzielen.

Das Erstellen separater Datenbanken funktioniert eventuell besser, wenn Sie Ihre Tabellen so auf die Datenbanken verteilen, dass jede Datenbank eine geringe Anzahl von Schemaänderungen pro Woche aufweist.

Wenn Sie bei Ihrer Anwendung für jeden Kunden separate Tabellen und Indexe erstellen, sollten Sie nicht alle Tabellen und Indexe in derselben Datenbank ablegen. Teilen Sie sie stattdessen auf viele Datenbanken auf, um Leistungsprobleme beim Erstellen einer großen Anzahl von Indexen zu minimieren.

Weitere Informationen zu anderen Datenverwaltungsmustern und dem Anwendungsdesign für die Mehrmandantenfähigkeit finden Sie unter Mehrmandantenfähigkeit in Cloud Spanner implementieren.