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:
- Hashen Sie den Schlüssel und speichern Sie ihn in einer Spalte. Verwenden Sie die Hash-Spalte (oder die Hash-Spalte und die Spalten mit dem eindeutigen Schlüssel) als Primärschlüssel.
- Vertauschen Sie die Reihenfolge der Spalten im Primärschlüssel.
- Verwenden Sie eine UUID (Universally Unique Identifier). Wir empfehlen die Version 4 von UUID, da bei dieser Version zufällige Werte in den Bits höherer Ordnung verwendet werden. Verwenden Sie keinen UUID-Algorithmus (beispielsweise Version 1 der UUID), bei dem der Zeitstempel in den Bits höherer Ordnung gespeichert wird.
- Bit-Umkehrungen für sequenzielle Werte
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:
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 SieNULL
-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
oderBYTES
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-Typenvarchar
undcharacter 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.
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.
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:
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 TabelleAlbums
ist, ist auch der Primärschlüssel der entsprechenden übergeordneten TabelleSingers
.- 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 AnnotationON 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örigenAlbums
-Zeilen bleiben unter der Split-Größenbeschränkung und es gibt keinen Hotspot in diesenAlbums
-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.
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:
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.
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
:
SingerId | FirstName | LastName |
---|---|---|
1 | Marc | Richards |
2 | Catalina | Smith |
SingerId | FirstName | LastName |
---|---|---|
1 | Alice | Trentor |
2 | Gabriel | Wright |
SingerId | FirstName | LastName |
---|---|---|
1 | Benjamin | Martinez |
2 | Hanna | Harris |
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:
CustomerId | SingerId | FirstName | LastName |
---|---|---|---|
1 | 1 | Marc | Richards |
1 | 2 | Catalina | Smith |
2 | 1 | Alice | Trentor |
2 | 2 | Gabriel | Wright |
3 | 1 | Benjamin | Martinez |
3 | 2 | Hanna | Harris |
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.