Schemaaktualisierungen vornehmen

Mit Spanner lassen sich Schemas ohne Ausfallzeit aktualisieren. Das Schema einer vorhandenen Datenbank kann mit verschiedenen Methoden aktualisiert werden:

Unterstützte Schemaaktualisierungen

Für das Schema einer vorhandenen Datenbank unterstützt Spanner folgende Arten von Aktualisierungen:

  • Ein benanntes Schema hinzufügen oder löschen.
  • Erstellen einer neuen Tabelle Spalten in neuen Tabellen können NOT NULL sein.
  • Eine Tabelle löschen, sofern keine anderen Tabellen damit verschränkt sind und die zu löschende Tabelle keine sekundären Indexe hat.
  • Erstellen oder Löschen einer Tabelle mit einem Fremdschlüssel.
  • Hinzufügen oder entfernen eines Fremdschlüssels aus einer vorhandenen Tabelle.
  • Eine Nicht-Schlüsselspalte in eine Tabelle aufnehmen. Neue Nicht-Schlüsselspalten dürfen nicht NOT NULL sein.
    • Eine Nicht-Schlüsselspalte aus einer Tabelle löschen, sofern sie nicht von einem sekundären Index, einem Fremdschlüssel, einer gespeicherten generierten Spalte oder einer Diagnoseeinschränkung verwendet wird.
  • NOT NULL in eine Nicht-Schlüsselspalte aufnehmen und dabei ARRAY-Spalten ausschließen.
  • NOT NULL aus einer Nicht-Schlüsselspalte entfernen.
  • Eine Spalte des Typs STRING in eine Spalte des Typs BYTES ändern oder umgekehrt (BYTES in STRING).
  • Eine Spalte des Typs PROTO in eine Spalte des Typs BYTES ändern oder umgekehrt (BYTES in PROTO).
  • Den Proto-Nachrichtentyp einer PROTO-Spalte ändern.
  • Fügen Sie einer ENUM-Definition neue Werte hinzu und benennen Sie vorhandene Werte mit ALTER PROTO BUNDLE um.
  • Ändern Sie Nachrichten, die in einem PROTO BUNDLE definiert sind, beliebig, sofern geänderte Felder dieser Nachrichten nicht als Schlüssel in einer Tabelle verwendet werden und die vorhandenen Daten den neuen Einschränkungen entsprechen.
  • Die Längenbeschränkung für einen STRING- oder BYTES-Typ erhöhen oder verringern (einschließlich auf MAX), es sei denn, es ist eine Primärschlüsselspalte, die von einer oder mehreren untergeordneten Tabellen übernommen wird.
  • Die Längenbeschränkung für eine Spalte vom Typ ARRAY<STRING>, ARRAY<BYTES> oder ARRAY<PROTO> auf das maximal zulässige Limit erhöhen oder verringern.
  • Commit-Zeitstempel in Wert- und Primärschlüsselspalten aktivieren oder deaktivieren.
  • Einen sekundären Index hinzufügen oder entfernen.
  • Diagnoseeinschränkung zu einer vorhandenen Tabelle hinzufügen oder daraus entfernen.
  • Gespeicherte generierte Spalte zu einer vorhandenen Tabelle hinzufügen oder daraus entfernen.
  • Erstellt ein neues Statistikpaket für das Optimierungstool.
  • Ansichten erstellen und verwalten.
  • Sequenzen erstellen und verwalten.
  • Datenbankrollen erstellen und Berechtigungen erteilen
  • Standardwert einer Spalte festlegen, ändern oder löschen
  • Ändern Sie die Datenbankoptionen (z. B. default_leader oder version_retention_period).
  • Änderungsstreams erstellen und verwalten.
  • ML-Modelle erstellen und verwalten

Nicht unterstützte Schemaaktualisierungen

Die folgenden Schemaaktualisierungen einer vorhandenen Datenbank werden von Spanner nicht unterstützt:

  • Wenn ein Feld PROTO vom Typ ENUM vorhanden ist, auf das von einem Tabellen- oder Indexschlüssel verwiesen wird, können Sie ENUM-Werte nicht aus den Proto-Enums entfernen. Das Entfernen von ENUM-Werten aus Enums, die von ENUM<>-Spalten verwendet werden, wird unterstützt, auch wenn diese Spalten als Schlüssel verwendet werden.

  • Eine Spalte des Typs STRING(36) in eine Spalte des Typs UUID ändern oder umgekehrt (UUID in STRING(36)).

Leistung während der Schemaaktualisierung

Schemaaktualisierungen in Spanner erfolgen ohne Ausfallzeiten. Wenn Sie einen Batch von DDL-Anweisungen an eine Spanner-Datenbank absetzen, können Sie ohne Unterbrechung weiter Daten in die Datenbank schreiben und aus ihr lesen, während Spanner die Aktualisierung als Vorgang mit langer Ausführungszeit durchführt.

Die Ausführungsdauer einer DDL-Anweisung hängt davon ab, ob die Aktualisierung eine Validierung von vorhandenen Daten oder einen Daten-Backfill voraussetzt. Wenn Sie beispielsweise die Annotation NOT NULL in eine vorhandene Spalte aufnehmen, muss Spanner alle Werte in der Spalte lesen und so gewährleisten, dass die Spalte keine NULL-Werte enthält. Dieser Schritt kann lange dauern, wenn viele Daten validiert werden müssen. Ein anderes Beispiel ist die Erweiterung einer Datenbank um einen Index: Spanner verwendet dann vorhandene Daten, um einen Backfill für den Index durchzuführen. In Abhängigkeit von der Definition des Index und der Größe der entsprechenden Basistabelle kann dieser Prozess viel Zeit in Anspruch nehmen. Wenn Sie jedoch eine neue Spalte in eine Tabelle einfügen, müssen keine vorhandenen Daten validiert werden, sodass Spanner die Aktualisierung schneller abwickeln kann.

Zusammenfassend lässt sich sagen, dass Schemaaktualisierungen innerhalb von Minuten durchgeführt werden können, wenn Spanner keine vorhandenen Daten validieren muss. Schemaaktualisierungen mit Validierung können je nach Menge der zu validierenden vorhandenen Daten länger dauern. Allerdings erfolgt die Datenvalidierung im Hintergrund mit niedrigerer Priorität als Produktionstraffic. Schemaaktualisierungen, die eine Datenvalidierung voraussetzen, werden im nächsten Abschnitt ausführlicher erläutert.

Schemaaktualisierungen, die mit Ansichtsdefinitionen validiert werden

Wenn Sie ein Schema aktualisieren, prüft Spanner, ob die Abfragen, die zum Definieren vorhandener Ansichten verwendet werden, durch das Update nicht ungültig werden. Ist die Validierung erfolgreich, verläuft auch die Schemaaktualisierung erfolgreich. Wenn die Validierung nicht erfolgreich ist, schlägt die Schemaaktualisierung fehl. Weitere Informationen finden Sie unter Best Practices beim Erstellen von Ansichten.

Schemaaktualisierungen mit erforderlicher Datenvalidierung

Sie können Schemaaktualisierungen vornehmen, bei denen überprüft werden muss, ob die vorhandenen Daten den neuen Einschränkungen entsprechen. Wenn für eine Schemaaktualisierung eine Datenvalidierung erforderlich ist, lässt Spanner keine in Konflikt stehenden Schemaaktualisierungen der betroffenen Schemaentitäten zu und validiert die Daten im Hintergrund. Ist die Validierung erfolgreich, verläuft auch die Schemaaktualisierung erfolgreich. Wenn die Validierung nicht erfolgreich ist, gilt das auch für die Schemaaktualisierung. Validierungsvorgänge sind lang laufende Vorgänge. Anhand des Status dieser Vorgänge können Sie feststellen, ob sie erfolgreich beendet wurden oder fehlgeschlagen sind.

Angenommen, Sie haben die folgende music.proto-Datei mit einem RecordLabel-Enum und einer Songwriter-Protokollnachricht definiert:

  enum RecordLabel {
    COOL_MUSIC_INC = 0;
    PACIFIC_ENTERTAINMENT = 1;
    XYZ_RECORDS = 2;
  }

  message Songwriter {
    required string nationality   = 1;
    optional int64  year_of_birth = 2;
  }

So fügen Sie Ihrem Schema eine Songwriters-Tabelle hinzu:

GoogleSQL

CREATE PROTO BUNDLE (
  googlesql.example.music.Songwriter,
  googlesql.example.music.RecordLabel,
);

CREATE TABLE Songwriters (
  Id         INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  Nickname   STRING(MAX),
  OpaqueData BYTES(MAX),
  SongWriter googlesql.example.music.Songwriter
) PRIMARY KEY (Id);

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

In diesem Fall sind folgende Schemaaktualisierungen zulässig, die jedoch validiert werden müssen und je nach Menge der vorhandenen Daten länger dauern können:

  • Die Annotation NOT NULL in eine Nicht-Schlüsselspalte aufnehmen. Beispiel:

    ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
    
  • Die Länge einer Spalte verringern. Beispiel:

    ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
    
  • BYTES in STRING ändern. Beispiel:

    ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
    
  • INT64/INT32 in ENUM ändern. Beispiel:

    ALTER TABLE Albums ALTER COLUMN Label googlesql.example.music.RecordLabel;
    
  • Vorhandene Werte aus der Enum-Definition RecordLabel entfernen.

  • Commit-Zeitstempel für eine vorhandene TIMESTAMP-Spalte aktivieren. Beispiel:

    ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
    
  • Diagnoseeinschränkung zu einer vorhandenen Tabelle hinzufügen

  • Gespeicherte generierte Spalte zu einer vorhandenen Tabelle hinzufügen

  • Erstellen einer neuen Tabelle mit einem Fremdschlüssel.

  • Einer vorhandenen Tabelle einen Fremdschlüssel hinzufügen

Diese Schemaaktualisierungen schlagen fehl, wenn die zugrunde liegenden Daten den neuen Einschränkungen nicht entsprechen. Beispielsweise schlägt die Anweisung ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL fehl, wenn in der Spalte Nickname ein Wert NULL ist. In diesem Fall entsprechen die vorhandenen Daten nicht der Einschränkung NOT NULL der neuen Definition.

Die Datenvalidierung kann mehrere Minuten bis viele Stunden andauern. Die Dauer der Datenvalidierung hängt von folgenden Faktoren ab:

  • Größe des Datasets
  • Rechenkapazität der Instanz
  • Auslastung der Instanz

Einige Schemaaktualisierungen können das Verhalten von Anfragen an die Datenbank während der Schemaaktualisierung ändern. Wenn Sie beispielsweise NOT NULL in eine Spalte aufnehmen, beginnt Spanner nahezu sofort damit, Schreibvorgänge für neue Anfragen abzulehnen, in denen NULL für diese Spalte angegeben ist. Sollte die neue Schemaaktualisierung aufgrund der Datenvalidierung letztendlich fehlschlagen, wurden Schreibvorgänge in einem gewissen Zeitraum blockiert, auch wenn sie vom alten Schema akzeptiert worden wären.

Sie können einen lang andauernden Datenvalidierungsprozess mit der Methode projects.instances.databases.operations.cancel oder mit gcloud spanner operations abbrechen.

Während der Schemaaktualisierung erstellte Schemaversionen

Da Spanner mit Schemaversionierung arbeitet, können Schemas von großen Datenbanken ohne Ausfallzeit aktualisiert werden. Spanner behält die ältere Schemaversion bei, sodass Lesevorgänge während der Verarbeitung der Schemaaktualisierung möglich sind. Anschließend erstellt Spanner eine oder mehrere neue Versionen des Schemas, um die Schemaaktualisierung zu verarbeiten. Jede Version enthält das Ergebnis einer Gruppe von Anweisungen in einer einzelnen atomaren Änderung.

Die Schemaversionen stimmen nicht zwangsläufig eins zu eins mit Batches von DDL-Anweisungen oder einzelnen DDL-Anweisungen überein. Manche einzelne DDL-Anweisungen führen zu mehreren Schemaversionen, beispielsweise die Indexerstellung für vorhandene Basistabellen oder Anweisungen, die eine Datenvalidierung erfordern. In anderen Fällen können mehrere DDL-Anweisungen in einer einzigen Version zusammengefasst sein. Alte Schemaversionen können erhebliche Server- und Speicherressourcen verbrauchen und werden aufbewahrt, bis sie abgelaufen bzw. nicht mehr erforderlich sind, um Lesevorgänge von früheren Datenversionen bereitzustellen.

Die folgende Tabelle zeigt, wie lange Spanner benötigt, um ein Schema zu aktualisieren.

Schemavorgang Geschätzte Dauer
CREATE TABLE Minuten
CREATE INDEX

Minuten bis Stunden, wenn die Basistabelle vor dem Index erstellt wird.

Minuten, wenn die Anweisung gleichzeitig mit der Anweisung CREATE TABLE für die Basistabelle ausgeführt wird.

DROP TABLE Minuten
DROP INDEX Minuten
ALTER TABLE ... ADD COLUMN Minuten
ALTER TABLE ... ALTER COLUMN

Minuten bis Stunden, wenn eine Validierung im Hintergrund erforderlich ist.

Minuten, wenn keine Validierung im Hintergrund erforderlich ist.

ALTER TABLE ... DROP COLUMN Minuten
ANALYZE

Je nach Datenbankgröße kann es einige Minuten bis Stunden dauern.

Änderungen des Datentyps und Änderungsstreams

Wenn Sie den Datentyp einer Spalte ändern, die von einem Änderungsstream überwacht wird, spiegelt das Feld column_types der relevanten nachfolgenden Änderungsstreamdatensätze den neuen Typ wider, ebenso wie die old_values-JSON-Daten im Feld mods der Datensätze.

Der new_values des Felds mods eines Änderungsstreamdatensatzes entspricht immer dem aktuellen Typ einer Spalte. Wenn Sie den Datentyp einer beobachteten Spalte ändern, wirkt sich das nicht auf Änderungsstreamdatensätze aus, die vor dieser Änderung erstellt wurden.

Im speziellen Fall einer Änderung von BYTES zu STRING werden die alten Werte der Spalte im Rahmen der Schemaaktualisierung von Spanner validiert. Daher hat Spanner die alten Werte vom Typ BYTES sicher in Strings decodiert, bevor nachfolgende Änderungsstreamdatensätze geschrieben werden.