Schemas – Übersicht

Auf dieser Seite werden die Anforderungen an Spanner-Schemas, die Verwendung des Schemas zum Erstellen hierarchischer Beziehungen und Schemafunktionen erläutert. Außerdem werden verschränkte Tabellen eingeführt, mit denen sich die Abfrageleistung bei Abfragen von Tabellen in einer übergeordneten/untergeordneten Beziehung verbessern lässt.

Ein Schema ist ein Namespace, der Datenbankobjekte wie Tabellen, Ansichten, Indexe und Funktionen enthält. Mit Schemas können Sie Objekte organisieren, detaillierte Zugriffssteuerungsberechtigungen anwenden und Namenskollisionen vermeiden. Sie müssen für jede Datenbank in Spanner ein Schema definieren.

Außerdem können Sie Zeilen in Ihrer Datenbanktabelle in verschiedenen geografischen Regionen weiter segmentieren und speichern. Weitere Informationen finden Sie unter Geo-Partitionierung.

Daten mit starker Typisierung

Daten in Spanner sind stark typisiert. Zu den Datentypen gehören skalare und komplexe Typen, die unter Datentypen in GoogleSQL und PostgreSQL-Datentypen beschrieben werden.

Primärschlüssel auswählen

Spanner-Datenbanken können eine oder mehrere Tabellen enthalten. Tabellen sind in Zeilen und Spalten strukturiert. Im Tabellenschema werden eine oder mehrere Tabellenspalten als Primärschlüssel der Tabelle definiert, mit dem jede Zeile eindeutig identifiziert wird. Primärschlüssel sind immer für die schnelle Zeilensuche indexiert. 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 enthalten. Nur Datenbanken mit GoogleSQL-Dialekt können Tabellen ohne Primärschlüssel haben.

Oft hat Ihre Anwendung bereits ein Feld, das als Primärschlüssel verwendet werden kann. In einer Customers-Tabelle kann beispielsweise eine von einer Anwendung bereitgestellte CustomerId vorhanden sein, die als Primärschlüssel dient. In anderen Fällen müssen Sie eventuell beim Einfügen einer Zeile einen Primärschlüssel generieren. Dies ist in der Regel ein eindeutiger Ganzzahlwert ohne geschäftliche Bedeutung (ein surrogater 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 zwischen den Servern nach Schlüsselbereichen aufteilt. Dies bedeutet, dass Ihre Einfügungen auf einen einzelnen Server gerichtet werden und einen Hotspot bilden. Mit diesen Verfahren können Sie die Last auf mehrere Server verteilen und Hotspots vermeiden:

Hierarchische Tabellenbeziehungen

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

Die Tabellenverschränkung von Spanner eignet sich gut für viele über-/untergeordnete Beziehungen. Bei der Verschränkung platziert Spanner untergeordnete Zeilen physisch zusammen mit übergeordneten Zeilen im Speicher. Die gemeinsame Anordnung kann die Leistung erheblich verbessern. Wenn Sie beispielsweise eine Tabelle Customers und eine Tabelle Invoices haben und Ihre Anwendung ruft häufig alle Rechnungen für einen bestimmten Kunden ab, können Sie Invoices als verschränkte untergeordnete Tabelle von Customers definieren. Damit 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 ordnen eine untergeordnete Tabelle einer übergeordneten Tabelle zu, indem Sie DDL verwenden, um die untergeordnete Tabelle als verschränkt in der übergeordneten Tabelle zu deklarieren, und den Primärschlüssel der übergeordneten Tabelle als ersten Teil des zusammengesetzten Primärschlüssels der untergeordneten Tabelle angeben. Weitere Informationen zur Verschränkung von Tabellen finden Sie weiter unten auf dieser Seite 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 in verschränkten Tabellen

Für das Interleaving 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 Spalten der untergeordneten Tabelle enthält.

Spanner speichert Zeilen in einer 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: Mit Spanner können Sie Zeilen relationaler Tabellen physisch gemeinsam speichern. Die Schemabeispiele zeigen, wie dieses physische Layout aussieht.

Datenbankaufteilungen

Sie können Hierarchien von verschränkten Beziehungen zwischen übergeordneten und untergeordneten Elementen mit bis zu sieben Ebenen definieren, was bedeutet, dass Sie Zeilen mit sieben unabhängigen Tabellen zusammen unterbringen können. Wenn die Größe der Daten in Ihren Tabellen gering ist, kann Ihre Datenbank wahrscheinlich von einem einzigen Spanner-Server verarbeitet werden. Aber was passiert, wenn Ihre relationalen Tabellen wachsen und die Ressourcengrenzen eines einzelnen Servers erreichen? Spanner ist eine verteilte Datenbank. Das bedeutet, dass Spanner die Daten in Portionen aufteilt, die als „Splits“ bezeichnet werden, wenn die Datenbank wächst. Aufteilungen können sich unabhängig voneinander bewegen 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 entsprechend der Größe und Last hinzu und entfernt sie. Dadurch verändert sich die Anzahl der Splits in der Datenbank.

Lastbasierte Aufteilung

Als Beispiel dafür, wie Spanner die lastbasierte Aufteilung zur Vermeidung von Hotspots vornimmt, gehen Sie erst einmal davon aus, dass Ihre Datenbank eine Tabelle mit 10 Zeilen enthält, die öfter gelesen werden als alle anderen Zeilen in der Tabelle. Spanner kann Split-Grenzen zwischen jeder dieser 10 Zeilen einfügen, sodass sie alle von einem anderen Server verarbeitet werden, anstatt dass alle Lesevorgänge dieser Zeilen die Ressourcen eines einzelnen Servers verbrauchen können.

Wenn Sie die Best Practices für das Schemadesign befolgen, kann Spanner Hotspots in der Regel so abmildern, dass sich der Lesedurchsatz alle paar Minuten verbessern sollte, bis die Ressourcen in Ihrer Instanz ausgelastet sind oder keine neuen Split-Grenzen hinzugefügt werden können, weil ein Split nur eine einzelne Zeile ohne verschränkte untergeordnete Zeilen abdeckt.

Benannte Schemas

Mit benannten Schemas können Sie ähnliche Daten zusammenfassen. So können Sie Objekte in der Google Cloud -Console schnell finden, Berechtigungen anwenden und Namenskollisionen vermeiden.

Benannte Schemas werden wie andere Datenbankobjekte mithilfe von DDL verwaltet.

Bei benannten Spanner-Schemas können Sie voll qualifizierte Namen (Fully Qualified Names, FQNs) verwenden, um Daten abzufragen. Mit vollständig qualifizierten Objektnamen können Sie den Schemanamen und den Objektnamen kombinieren, um Datenbankobjekte zu identifizieren. Sie könnten beispielsweise ein Schema namens warehouse für die Lagerabteilung erstellen. Beispiele für Tabellen, die dieses Schema verwenden, sind product, order und customer information. Alternativ können Sie ein Schema mit dem Namen fulfillment für die Auftragsausführung erstellen. Dieses Schema könnte auch Tabellen mit den Namen product, order und customer information enthalten. Im ersten Beispiel ist warehouse.product der vollständige Pfadname und im zweiten Beispiel fulfillment.product. So wird verhindert, dass es zu Verwechslungen kommt, wenn mehrere Objekte denselben Namen haben.

In der CREATE SCHEMA-DDL erhalten Tabellenobjekte sowohl einen vollständigen Bezeichner, z. B. sales.customers, als auch einen Kurznamen, z. B. sales.

Die folgenden Datenbankobjekte unterstützen benannte Schemas:

  • TABLE
    • CREATE
    • INTERLEAVE IN [PARENT]
    • FOREIGN KEY
    • SYNONYM
  • VIEW
  • INDEX
  • FOREIGN KEY
  • SEQUENCE

Weitere Informationen zur Verwendung benannter Schemas finden Sie unter Benannte Schemas verwalten.

Detaillierte Zugriffssteuerung mit benannten Schemas verwenden

Mit benannten Schemas können Sie jedem Objekt im Schema Zugriff auf Schemaebene gewähren. Das gilt für Schemaobjekte, die zum Zeitpunkt der Zugriffsberechtigung vorhanden sind. Sie müssen Zugriff auf Objekte gewähren, die später hinzugefügt werden.

Die detaillierte Zugriffssteuerung schränkt den Zugriff auf ganze Gruppen von Datenbankobjekten ein, z. B. Tabellen, Spalten und Zeilen in der Tabelle.

Weitere Informationen finden Sie unter Berechtigungen für die detaillierte Zugriffssteuerung für benannte Schemas gewähren.

Schemabeispiele

Die Schemabeispiele in diesem Abschnitt zeigen, wie Sie über- und untergeordnete Tabellen mit und ohne Verschränkung erstellen, und veranschaulichen die entsprechenden physischen Layouts der Daten.

Übergeordnete Tabelle erstellen

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

Tabelle „Sänger“ mit fünf Zeilen und vier Spalten

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

Sie können die Tabelle mit der folgenden DDL definieren:

GoogleSQL

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

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 im Stammverzeichnis der Datenbankhierarchie, da sie nicht als verschränktes untergeordnetes Element einer anderen Tabelle definiert ist.
  • Bei GoogleSQL-Datenbanken sind Primärschlüsselspalten in der Regel mit NOT NULL annotiert. Sie können diese Annotation jedoch weglassen, wenn NULL-Werte in Schlüsselspalten zulässig sein sollen. 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 in dem Feld gespeichert werden können. Die Längenspezifikation ist für die PostgreSQL-Typen varchar und character varying optional. Weitere Informationen finden Sie unter Skaläre Datentypen für Datenbanken mit GoogleSQL-Dialekt und PostgreSQL-Datentypen für Datenbanken mit PostgreSQL-Dialekt.

Wie sieht das physische Layout der Zeilen in der Tabelle Singers aus? Das folgende Diagramm zeigt Zeilen der Tabelle Singers, die nach dem Primärschlüssel gespeichert wurden („Sänger(1)“ und dann „Sänger(2)“, wobei die Zahl in Klammern der Primärschlüsselwert ist.

Beispielzeilen einer Tabelle in Primärschlüsselreihenfolge

Das obige Diagramm zeigt eine Beispiel-Split-Grenze zwischen den Zeilen, die mit Singers(3) und Singers(4) codiert sind. Dabei sind die Daten aus den entstandenen Splits verschiedenen Servern zugewiesen. Das bedeutet, dass mit dieser Tabelle Zeilen von Singers-Daten an verschiedenen Standorten gespeichert werden können.

Übergeordnete und untergeordnete Tabellen erstellen

Angenommen, Sie möchten jetzt in der Musikanwendung einige grundlegende Daten zum Album jedes Sängers hinzufügen.

Tabelle „Alben“ mit fünf Zeilen und drei Spalten

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. Das im Folgenden aufgeführte Beispielschema definiert sowohl die Albums- als auch die Singers-Tabelle im Stamm der Datenbankhierarchie. Damit sind diese Tabellen hierarchisch gleichgeordnet.

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

GoogleSQL

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

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 gleicht dem des folgenden Diagramms. 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 von Zeilen

Wichtiger Hinweis zum Schema: Spanner geht von keiner Datenlokalitätsbeziehung zwischen den Tabellen Singers und Albums aus, da es sich um übergeordnete Tabellen handelt. Wenn die Datenbank wächst, kann Spanner Split-Grenzen zwischen allen Zeilen einfü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 Lese- und Schreibvorgänge ü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, damit Zeilen aus beiden Tabellen unter der Primärschlüsseldimension gemeinsam gespeichert 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 zusammen 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.

Wenn Sie eine Tabelle verschachteln, ist dies nicht rückgängig zu machen. Das Interleaving kann nicht rückgängig gemacht werden. Stattdessen müssen Sie die Tabelle neu erstellen und die Daten dorthin migrieren.

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

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

Die fett dargestellte Zeile im folgenden Schema zeigt, wie Albums als verschränkte Tabelle von Singers erstellt wird.

GoogleSQL

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

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 erste Teil des Primärschlüssels der untergeordneten Tabelle Albums, ist auch der Primärschlüssel der übergeordneten Tabelle Singers.
  • Die Annotation ON DELETE CASCADE bedeutet, dass beim Löschen einer Zeile der übergeordneten Tabelle die Zeile der entsprechenden untergeordneten Tabelle automatisch ebenfalls gelöscht wird. Wenn eine untergeordnete Tabelle diese Annotation nicht enthält oder die Annotation ON DELETE NO ACTION lautet, 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 mit dem Primärschlüssel des übergeordneten Elements sortiert. Beispiel: „Sänger(1)“, dann „Alben(1, 1)“ und dann „Alben(1, 2)“.
  • Die Datenlokalitätsbeziehung zwischen jedem Sänger und dessen Albumdaten bleibt erhalten, wenn diese Datenbank aufgeteilt wird, sofern die Größe einer Singers-Zeile und aller ihrer Albums-Zeilen unter dem Grenzwert für die Größe des Splits bleibt und es keinen Hotspot in einer dieser Albums-Zeilen gibt.
  • 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 dem Einfügen der untergeordneten Zeilen in derselben Transaktion eingefügt werden.

„Albums“-Zeilen sind zwischen „Singers“-Zeilen verschränkt

Eine 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 sechs Zeilen und vier Spalten

Songs muss einen Primärschlüssel haben, der alle Primärschlüssel der Tabellen auf einer höheren Hierarchieebene 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 PRIMARY KEY,
 FirstName  STRING(1024),
 LastName   STRING(1024),
 SingerInfo BYTES(MAX),
);

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.

Songs sind in Alben verschränkt und Alben sind zwischen Sängern verschränkt

In diesem Beispiel fügt Spanner bei zunehmender Anzahl von Sängern Split-Grenzen zwischen den Sängern hinzu, um die Datenlokalität zwischen einem Sänger und seinen Album- und Songdaten beizubehalten. Wenn die Größe einer Sängerzeile und ihrer untergeordneten Zeilen jedoch das Limit für die Größe von Splits überschreitet oder in den untergeordneten Zeilen ein Hotspot 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, können Sie durch diese physische Verschränkung die Leistung verbessern, da die Tabellen schon vorab verknüpft werden. Dadurch können Sie auf die Zeilen der relationalen Tabellen zusammen zugreifen und gleichzeitig die Zugriffe auf den Speicher minimieren.

Joins mit verschachtelten Tabellen

Verbinden Sie nach Möglichkeit Daten in verschränkten Tabellen mit dem Primärschlüssel. Da jede verschränkte Zeile normalerweise physisch in demselben Split wie die entsprechende übergeordnete Zeile gespeichert ist, kann Spanner lokale Zusammenführungen mit dem Primärschlüssel durchführen und so den Zugriff auf das Speichersystem und den Netzwerkverkehr 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 wichtigen Spalten.

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. In PostgreSQL-Datenbanken werden keine NULL-Werte in einer Primärschlüsselspalte unterstützt.

Das folgende Beispiel zeigt das Weglassen der NOT NULL-Klausel in der Primärschlüsselspalte SingerId. Da SingerId der Primärschlüssel ist, kann maximal eine Zeile in der entsprechenden Spalte vorhanden sein, der NULL gespeichert ist.

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

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 es in Singers.SingerId fehlt.

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

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 können nicht vom Typ ARRAY sein:

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

Mehrinstanzenfähigkeit berücksichtigen

Falls Sie Daten speichern, die verschiedenen Kunden gehören, möchten Sie eventuell für Mehrinstanzenfähigkeit sorgen. Zum Beispiel kann es für einen Musikdienst von Interesse sein, die Inhalte jedes einzelnen Plattenlabels separat zu speichern.

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 Mehrinstanzenfähigkeit

Eine weitere Möglichkeit der Entwicklung für die Mehrmandantenfähigkeit in Spanner besteht darin, alle Kunden in einer einzigen Tabelle in einer einzigen Datenbank anzulegen und für jeden Kunden einen anderen Primärschlüsselwert zu verwenden. Sie können beispielsweise eine Spalte mit dem Schlüssel CustomerId 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 effektiv Datenbank-Splits verwenden, um die Leistung anhand von Datengröße und Lademustern zu maximieren. Im folgenden Beispiel gibt es eine einzige Singers-Tabelle für alle Kunden:

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

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

  • Es gelten Beschränkungen für die Anzahl der Datenbanken pro Instanz und für die Anzahl der Tabellen und Indexe pro Datenbank. Je nach Kundenanzahl ist es gegebenenfalls 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 zum Anwendungsdesign für die Mehrfachnutzung finden Sie unter Mehrfachnutzung in Spanner implementieren.