Schemas – Übersicht

Auf dieser Seite werden die Anforderungen für das Spanner-Schema, die Verwendung des Schemas zum Erstellen hierarchischer Beziehungen und die Schemafeatures erläutert. Außerdem werden verschränkte Tabellen eingeführt, was die Abfrageleistung beim Abfragen von Tabellen in einer hierarchischen Beziehung verbessern kann.

Ein Schema ist ein Namespace, der Datenbankobjekte wie Tabellen, Ansichten, Indexe und Funktionen enthält. Sie verwenden Schemas, um Objekte zu organisieren, differenzierte Zugriffssteuerungsberechtigungen anzuwenden und Namenskonflikte zu vermeiden. Sie müssen in Spanner für jede Datenbank ein Schema definieren.

Stark typisierte Daten

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 als Zeilen und Spalten strukturiert. Das Tabellenschema definiert eine oder mehrere Tabellenspalten als Primärschlüssel der Tabelle, der jede Zeile eindeutig identifiziert. Primärschlüssel werden immer für eine 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 haben. Nur GoogleSQL-Dialekt-Datenbanken können Tabellen ohne Primärschlüssel haben.

Häufig hat Ihre Anwendung bereits ein Feld, das sich gut als Primärschlüssel verwenden lässt. Für eine Tabelle vom Typ Customers kann beispielsweise ein von der Anwendung bereitgestelltes CustomerId vorhanden sein, das als Primärschlüssel dient. In anderen Fällen müssen Sie beim Einfügen der Zeile möglicherweise einen Primärschlüssel generieren. Dies ist in der Regel eine eindeutige Ganzzahl ohne geschäftliche Signifikanz (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 zwischen den Servern nach Schlüsselbereichen aufteilt. Das bedeutet, dass die Einfügungen an einen einzelnen Server gerichtet werden und dadurch einen Hotspot entstehen. Mit diesen Verfahren können Sie die Last auf mehrere Server verteilen und Hotspots vermeiden:

Hierarchische Tabellenbeziehungen

Es gibt zwei Möglichkeiten, Beziehungen zwischen über- und untergeordneten Elementen in Spanner zu definieren: mit Tabellenverschränkung und Fremdschlüssel.

Die Tabellenverschränkung von Spanner ist eine gute Wahl für viele über- und untergeordnete Beziehungen. Durch die Verschränkung ordnet Spanner untergeordnete Zeilen im Speicher den übergeordneten Zeilen zu. Eine Colocations-Einrichtung kann die Leistung erheblich verbessern. Wenn Sie beispielsweise eine Customers- 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 mit einer übergeordneten Tabelle, indem Sie DDL verwenden, die die untergeordnete Tabelle als mit der übergeordneten Tabelle verschränkt deklariert, und indem Sie den Primärschlüssel der übergeordneten Tabelle als ersten Teil des zusammengesetzten Primärschlüssels der untergeordneten Tabelle einfügen. Weitere Informationen zur Verschränkung 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 unter Fremdschlüssel.

Primärschlüssel in verschränkten Tabellen

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

Spanner speichert Zeilen in einer sortierten Reihenfolge nach Primärschlüsselwerten, wobei zwischen den übergeordneten Zeilen untergeordnete Zeilen eingefügt werden. Eine Abbildung verschränkter Zeilen finden Sie weiter unten auf dieser Seite unter Verschränkte Tabellen erstellen.

Zusammenfassend lässt sich sagen, dass Spanner Zeilen zusammengehöriger Tabellen physisch zusammenfassen kann. Die Schemabeispiele zeigen, wie dieses physische Layout aussieht.

Datenbankaufteilungen

Sie können Hierarchien von verschränkten hierarchischen Beziehungen mit bis zu sieben Ebenen definieren. Das bedeutet, dass Sie Zeilen mit sieben unabhängigen Tabellen gruppieren können. Wenn die Daten in Ihren Tabellen klein sind, kann wahrscheinlich ein einzelner Spanner-Server die Datenbank verarbeiten. Aber was passiert, wenn die zugehörigen Tabellen wachsen und die Ressourcenlimits eines einzelnen Servers erreichen? Spanner ist eine verteilte Datenbank. Das bedeutet, dass Spanner die Daten mit zunehmendem Umfang der Datenbank in Portionen aufteilt, die als „Splits“ bezeichnet werden. 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 eine Reihe zusammenhängender Zeilen. Die Start- und Endschlüssel dieses Bereichs werden als "Split-Grenzen" bezeichnet. Spanner fügt automatisch Split-Grenzen basierend auf Größe und Last hinzu und entfernt sie, wodurch sich die Anzahl der Splits in der Datenbank ändert.

Lastbasierte Aufteilung

Angenommen, Ihre Datenbank enthält eine Tabelle mit 10 Zeilen, die häufiger als alle anderen Zeilen in der Tabelle gelesen werden. Hier ein Beispiel dafür, wie Spanner eine lastbasierte Aufteilung zur Reduzierung von Lese-Hotspots durchführt. Spanner kann Split-Grenzen zwischen diesen 10 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.

Allgemein gilt: Wenn Sie die Best Practices für das Schemadesign befolgen, kann Spanner Hotspots abschwächen. Dadurch sollte sich der Lesedurchsatz alle paar Minuten verbessern, bis die Ressourcen in Ihrer Instanz ausgelastet sind. Es kann auch vorkommen, dass 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).

Benannte Schemas

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

Benannte Schemas werden wie andere Datenbankobjekte mit DDL verwaltet.

Mit benannten Spanner-Schemas können Sie vollständig qualifizierte Namen (Full Qualified Names, FQNs) zum Abfragen von Daten verwenden. Mit FQNs können Sie den Schemanamen und den Objektnamen kombinieren, um Datenbankobjekte zu identifizieren. Sie können beispielsweise ein Schema mit dem Namen warehouse für die Geschäftseinheit des Warenlagers erstellen. Die Tabellen, die dieses Schema verwenden, können product, order und customer information sein. Alternativ können Sie ein Schema mit dem Namen fulfillment für die Geschäftseinheit für die Auftragsausführung erstellen. Dieses Schema könnte auch Tabellen mit den Namen product, order und customer information enthalten. Im ersten Beispiel lautet die FQN warehouse.product und im zweiten Beispiel fulfillment.product. Dies verhindert Verwirrung in Situationen, in denen mehrere Objekte denselben Namen haben.

In der DDL-Datei CREATE SCHEMA erhalten Tabellenobjekte eine FQN (z. B. sales.customers) und 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. Dies gilt für Schemaobjekte, die vorhanden sind, wenn Sie Zugriff gewähren. Sie müssen Zugriff auf Objekte gewähren, die später hinzugefügt werden.

Eine differenzierte Zugriffssteuerung beschränkt den Zugriff auf ganze Gruppen von Datenbankobjekten, z. B. auf Tabellen, Spalten und Zeilen in der Tabelle.

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

Schemabeispiele

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

Übergeordnete Tabelle erstellen

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

Tabelle 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,
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 verschränktes untergeordnetes Element einer anderen Tabelle definiert ist).
  • Bei GoogleSQL-Dialekt-Datenbanken werden Primärschlüsselspalten normalerweise mit NOT NULL annotiert. Sie können diese Annotation jedoch weglassen, 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 der maximalen Anzahl von Unicode-Zeichen entspricht, die in dem 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-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üssel gespeichert sind ("Singers(1)", und dann "Singers(2)", wobei die Zahl in Klammern der Wert des Primärschlüssels ist.

Beispielzeilen einer Tabelle, die in Primärschlüsselreihenfolge gespeichert sind

Das obige Diagramm zeigt eine beispielhafte Split-Grenze zwischen den mit Singers(3) und Singers(4) codierten Zeilen, wobei die Daten aus den resultierenden Splits verschiedenen Servern zugewiesen werden. Wenn diese Tabelle wächst, ist es möglich, dass Singers-Datenzeilen an verschiedenen Orten gespeichert werden.

Übergeordnete und untergeordnete Tabellen erstellen

Angenommen, Sie möchten nun der Musikanwendung einige grundlegende Daten zu den Alben der einzelnen Sänger hinzufügen.

Album-Tabelle 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. Im folgenden Beispielschema werden die Tabellen Albums und Singers auf der Stammebene der Datenbankhierarchie definiert. Damit sind diese Tabellen gleichgestellt.

-- 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. Zeilen von Singers sind nach zusammenhängenden Primärschlüsseln gespeichert:

Physisches Layout von Zeilen

Ein wichtiger Hinweis zum 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 allen 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önnten und die beiden Splits sich unabhängig voneinander bewegen könnten.

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 für verschiedene Ressourcen 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. Diese Tabelle ordnet Zeilen aus den beiden Tabellen entlang der Primärschlüsseldimension an. Im nächsten Beispiel wird dies genauer erläutert.

Verschränkte Tabellen erstellen

Eine verschränkte Tabelle ist eine Tabelle, die Sie als verschränktes untergeordnetes Element einer anderen Tabelle deklarieren, weil die Zeilen der untergeordneten Tabelle physisch 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 beim Entwerfen Ihrer Musikanwendung davon ausgehen, dass die Anwendung häufig auf Zeilen aus der Tabelle Albums zugreifen muss, wenn sie auf eine Singers-Zeile 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 müssen Singers und Albums eine starke Daten-Lokalitätsbeziehung haben. Sie können diese Datenlokalitätsbeziehung durch Erstellen von Albums als verschränkte untergeordnete Tabelle von Singers deklarieren.

-- 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 erste Teil des Primärschlüssels der untergeordneten Tabelle Albums, 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 zugehörigen untergeordneten Zeilen automatisch gelöscht werden. Wenn eine untergeordnete Tabelle diese Annotation nicht hat 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 geordnet, dann nach zusammenhängenden Zeilen der untergeordneten Tabelle, die den Primärschlüssel der übergeordneten Tabelle teilen. Beispiel: "Singers(1)", dann "Albums(1, 1)" und dann "Albums(1, 2)".
  • Die Daten-Lokalitätsbeziehung zwischen jedem Sänger und seinen Albumdaten bleibt erhalten, wenn diese Datenbank aufgeteilt wird, vorausgesetzt, dass die Größe einer Singers-Zeile und aller ihrer Albums-Zeilen unter dem Split-Größenlimit bleibt und in keiner dieser Albums-Zeilen kein Hotspot vorhanden ist.
  • 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ügung der untergeordneten Zeilen in dieselbe Transaktion eingefügt werden.

"Albums"-Zeilen sind zwischen "Albums"-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 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,
 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.

Songs sind in "Albums" verschränkt, die zwischen "Albums" verschränkt sind.

In diesem Beispiel fügt Spanner bei wachsender Anzahl von Sängern geteilte Grenzen zwischen Sängern hinzu, um die Datenlokalität zwischen einem Sänger und seinen Album- und Songdaten zu bewahren. Wenn die Größe einer Sängerzeile und ihrer untergeordneten Zeilen jedoch das Limit für die geteilte Größe überschreitet oder in den untergeordneten Zeilen ein Hotspot erkannt wird, versucht Spanner, Split-Grenzen hinzuzufügen, um diese Hotspotzeile zusammen mit allen untergeordneten Zeilen darunter 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 effektiv vorab verknüpft werden, sodass Sie zusammen auf zusammengehörige Zeilen zugreifen können und gleichzeitig Speicherzugriffe 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 normalerweise physisch im selben Split wie die übergeordnete Zeile gespeichert wird, kann Spanner lokale Joins anhand des Primärschlüssels ausführen und so den Speicherzugriff und den Netzwerktraffic minimieren. Im folgenden Beispiel werden Singers und Albums durch den Primärschlüssel SingerId verbunden.

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-Dialekte unterstützen keine NULL-Werte in Primärschlüsselspalten.

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

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 Singers.SingerId dies auslässt.

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

Entwicklung für Mehrmandantenfähigkeit

Sie können die Mehrmandantenfähigkeit implementieren, wenn Sie Daten speichern, die verschiedenen Kunden gehören. Beispielsweise kann ein Musikdienst die Inhalte der einzelnen Musiklabels separat speichern.

Klassische Mehrinstanzenfähigkeit

Der klassische Weg zur Entwicklung von Mehrmandantenfähigkeit besteht darin, für jeden Kunden eine separate 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

Durch Schema verwaltete 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 platzieren und für jeden Kunden einen anderen Primärschlüsselwert zu verwenden. Beispielsweise können Sie in Ihre Tabellen die Schlüsselspalte CustomerId einfügen. Wenn Sie CustomerId als erste Schlüsselspalte festlegen, ist die Lokalität der Daten für jeden Kunden gut. Spanner kann dann Datenbankaufteilungen effektiv nutzen, um die Leistung auf der Grundlage von Datengröße und Lademustern zu maximieren. Im folgenden Beispiel gibt es eine einzelne Singers-Tabelle für alle Kunden:

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

Wenn Sie für jeden Mandanten eine separate Datenbank benötigen, müssen Sie folgende Einschränkungen beachten:

  • Für die Anzahl der Datenbanken pro Instanz und die Anzahl der Tabellen und Indexe pro Datenbank gelten Limits. 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 Ihr Schemadesign vom Hinzufügen neuer Tabellen und Indexe abhängt, 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 für jeden Kunden Ihrer Anwendung separate Tabellen und Indexe erstellen, speichern Sie nicht alle Tabellen und Indexe in derselben Datenbank. Teilen Sie sie stattdessen auf viele Datenbanken auf, um Leistungsprobleme beim Erstellen einer großen Anzahl von Indexen zu verringern.

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