In diesem Dokument werden Best Practices für das Aktualisieren von Schemas beschrieben.
Vor der Schemaaktualisierung auszuführende Schritte
Führen Sie vor dem Aktualisieren eines Schemas folgende Schritte aus:
Prüfen Sie, ob alle vorhandenen Daten in der Datenbank den Einschränkungen entsprechen, die durch die Schemaaktualisierung eingeführt wurden. Da einige Schemaaktualisierungen von den tatsächlichen Daten und nicht nur vom aktuellen Schema abhängen, garantiert eine erfolgreiche Aktualisierung in einer Testdatenbank nicht, dass die Aktualisierung auch in einer Produktionsdatenbank erfolgreich ist. Hier ein paar gängige Beispiele:
- Achten Sie beim Hinzufügen der Annotation
NOT NULLzu einer vorhandenen Spalte darauf, dass in der Spalte keineNULL-Werte vorhanden sind. - Achten Sie beim Verringern der zulässigen Länge einer
STRING- oderBYTES-Spalte darauf, dass alle vorhandenen Werte in dieser Spalte der Längenbeschränkung entsprechen.
- Achten Sie beim Hinzufügen der Annotation
Wenn Sie in Spalten, Tabellen oder Indexe schreiben, die gerade einer Schemaaktualisierung unterzogen werden, sollten Sie prüfen, ob die von Ihnen geschriebenen Werte den neuen Einschränkungen entsprechen.
Achten Sie beim Löschen von Spalten, Tabellen oder Indexen darauf, dass Sie dafür keine Schreib- oder Lesevorgänge mehr ausführen.
Häufigkeit von Schemaaktualisierungen begrenzen
Wenn Sie innerhalb kurzer Zeit zu viele Schemaaktualisierungen vornehmen, kann Spanner die Verarbeitung von in die Warteschlange eingereihten Schemaaktualisierungen throttle. Das liegt daran, dass Spanner den Speicherplatz für Schemabereiche begrenzt. Ihre Schemaaktualisierung wird möglicherweise gedrosselt, wenn innerhalb des Aufbewahrungszeitraums zu viele alte Schemaversionen vorhanden sind. Die maximale Rate von Schemaänderungen hängt von vielen Faktoren ab, darunter die Gesamtzahl der Spalten in der Datenbank. In einer Datenbank mit 2.000 Spalten (etwa 2.000 Zeilen in INFORMATION_SCHEMA.COLUMNS) können beispielsweise maximal 1.500 Schemaänderungen innerhalb des Aufbewahrungszeitraums vorgenommen werden (weniger, wenn für die Schemaänderung mehrere Versionen erforderlich sind). Verwenden Sie den Befehl gcloud spanner operations
list und filtern Sie nach Vorgängen vom Typ DATABASE_UPDATE_DDL, um den Status laufender Schemaaktualisierungen zu sehen. Verwenden Sie den Befehl gcloud spanner operations
cancel und geben Sie die Vorgangs-ID an, um eine laufende Schemaaktualisierung abzubrechen.
Wie Ihre DDL-Anweisungen zusammengefasst werden und in welcher Reihenfolge sie in den einzelnen Batches ausgeführt werden, kann sich auf die Anzahl der resultierenden Schemaversionen auswirken. Um die Anzahl der Schemaaktualisierungen zu maximieren, die Sie in einem bestimmten Zeitraum ausführen können, sollten Sie Batching verwenden, das die Anzahl der Schemaversionen minimiert. Einige Richtlinien werden in großen Updates beschrieben.
Wie unter Schemaversionen beschrieben, erstellen einige DDL-Anweisungen mehrere Schemaversionen. Diese spielen für Überlegungen zum Batching und der Reihenfolge in jedem Batch eine wichtige Rolle. Es gibt zwei Haupttypen von Anweisungen, die möglicherweise mehrere Schemaversionen erstellen:
- Anweisungen, die möglicherweise einen Indexdaten-Backfill durchführen müssen, z. B.
CREATE INDEX. - Anweisungen, die Spanner zwingen, vorhandene Daten zu validieren, z. B. das Hinzufügen von
NOT NULLoder Längenbeschränkungen.
Diese Arten von Anweisungen führen jedoch nicht immer zu mehreren Schemaversionen. Spanner versucht zu erkennen, wann diese Arten von Anweisungen optimiert werden können, um die Verwendung mehrerer Schemaversionen zu vermeiden. Dies hängt vom Batching ab. Wenn beispielsweise eine CREATE INDEX-Anweisung im selben Batch wie eine CREATE TABLE-Anweisung für die Basistabelle des Index ohne dazwischenliegende Anweisungen für andere Tabellen erfolgt, müssen die Indexdaten nicht nachgefüllt werden, da Spanner garantieren kann, dass die Basistabelle zum Zeitpunkt der Indexerstellung leer ist. Im Abschnitt Große Aktualisierungen wird beschrieben, wie Sie diese Eigenschaft verwenden, um effizient viele Indexe zu erstellen.
Wenn Sie die DDL-Anweisungen nicht im Batch verarbeiten können, um das Erstellen von vielen Schemaversionen zu vermeiden, sollten Sie die Anzahl der Schemaaktualisierungen innerhalb der Aufbewahrungsdauer für das Schema einer einzelnen Datenbank beschränken. Verlängern Sie das Zeitfenster für Schemaaktualisierungen, damit Spanner frühere Versionen des Schemas entfernen kann, bevor neue Versionen erstellt werden.
- Für einige relationale Datenbankverwaltungssysteme gibt es Softwarepakete, die bei jeder Produktionsbereitstellung eine lange Reihe von Upgrade- und Downgrade-Schemaaktualisierungen auf die Datenbank anwenden. Diese Arten von Prozessen werden für Spanner nicht empfohlen.
- Spanner ist für die Verwendung von Primärschlüsseln zum Partitionieren von Daten für Lösungen mit Mehrinstanzfähigkeit optimiert. Wenn Sie eine Lösung mit Mehrinstanzfähigkeit verwenden, die separate Tabellen für jeden Kunden nutzt, kann es bei Schemaaktualisierungen für viele Kunden gleichzeitig zu einem großen Rückstand an Schemaaktualisierungsvorgängen kommen, die nur langsam abgearbeitet werden.
- Schemaaktualisierungen, die eine Validierung oder einen Index-Backfill erfordern, verwenden mehr Serverressourcen, da jede Anweisung intern mehrere Versionen des Schemas erstellt.
Ausführungsreihenfolge von Anweisungen in Batches
Wenn Sie die Google Cloud CLI, die REST API oder die RPC API verwenden, können Sie einen Batch von einer oder mehreren CREATE-, ALTER- oder DROP-Anweisungen absetzen.
Spanner wendet Anweisungen aus demselben Batch entsprechend der Reihenfolge an und hält beim ersten Fehler an. Wenn die Anwendung einer Anweisung zu einem Fehler führt, wird diese Anweisung zurückgesetzt. Die Ergebnisse von vorher angewendeten Anweisungen im Batch bleiben jedoch erhalten. Wenn Sie Anweisungen, die unvermeidliches Backfilling erfordern, parallel ausführen möchten (z. B. das Erstellen mehrerer Indexe für große, vorhandene Tabellen), sollten Sie diese Anweisungen in separaten Batches einreichen, da jedes Backfilling lange dauern kann. Wenn Sie hingegen eine neue Tabelle mit Indexen erstellen, empfiehlt es sich, die Anweisungen in einem einzelnen Batch zusammenzufassen (CREATE TABLE gefolgt von CREATE INDEX), um das Backfilling vollständig zu vermeiden.
Spanner kann Anweisungen aus verschiedenen Batches kombinieren und neu anordnen. Dies kann dazu führen, dass Anweisungen aus verschiedenen Batches zu einer atomaren Änderung zusammengefasst werden und diese Änderung dann auf die Datenbank angewendet wird. Die Ausführung von Anweisungen aus verschiedenen Batches erfolgt in jeder atomaren Änderung in zufälliger Reihenfolge. Wenn beispielsweise ein Batch von Anweisungen ALTER TABLE table_name ALTER COLUMN column_name STRING(50) enthält und ein anderer Batch von Anweisungen ALTER TABLE table_name ALTER COLUMN
column_name STRING(20), belässt Spanner diese Spalte in einem dieser beiden Zustände, wobei nicht angegeben ist, in welchem.
Optionen für umfangreiche Schemaaktualisierungen
Die beste Methode zum Erstellen einer Tabelle und einer großen Anzahl von Indexen für diese Tabelle besteht darin, alles zur selben Zeit zu erstellen, sodass nur eine Schemaversion erstellt wird. Es wird empfohlen, die Indexe unmittelbar nach der Tabelle in der Liste der DDL-Anweisungen zu erstellen. Sie können die Tabelle und ihre Indexe gleichzeitig mit der Datenbank oder als einzelnen großen Batch Anweisungen erstellen. Wenn Sie viele Tabellen mit jeweils vielen Indexen erstellen müssen, können Sie alle Anweisungen in einem einzigen Batch zusammenfassen. Sie können mehrere tausend Anweisungen in einem einzigen Batch zusammenfassen, wenn alle Anweisungen mithilfe einer einzigen Schemaversion gemeinsam ausgeführt werden können.
Wenn eine Anweisung einen Backfill für Indexdaten erfordert oder eine Datenvalidierung durchführt, kann sie nicht in einer einzelnen Schemaversion ausgeführt werden. Dies geschieht bei CREATE INDEX-Anweisungen, wenn die Basistabelle des Index bereits vorhanden ist, entweder weil sie in einem vorherigen Batch von DDL-Anweisungen erstellt wurde oder weil im Batch zwischen den Anweisungen CREATE TABLE und CREATE INDEX eine Anweisung vorhanden war, für die mehrere Schemaversionen erforderlich waren. In Spanner dürfen nicht mehr als zehn solche Anweisungen in einem einzelnen Batch vorhanden sein. Insbesondere die Indexerstellung, die Backfilling erfordert, verwendet mehrere Schemaversionen pro Index. Daher gilt als Faustregel, pro Tag nicht mehr als drei neue Indexe zu erstellen, die Backfilling erfordern. Dabei ist es unerheblich, wie das Batching erfolgt, es sei denn, Backfilling kann dadurch verhindert werden.
Dieser Batch Anweisungen verwendet beispielsweise eine einzige Schemaversion:
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
Im Gegensatz dazu verwendet dieser Batch viele Schemaversionen, weil UnrelatedIndex Backfilling erfordert (da seine Basistabelle bereits vorhanden sein musste) und dadurch werden alle folgenden Indexe gezwungen, ebenfalls Backfilling zu erfordern (auch wenn sie sich im selben Batch wie ihre Basistabellen befinden):
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, 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); CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
Es ist besser, die Erstellung von UnrelatedIndex an das Ende des Batches oder in einen anderen Batch zu verschieben, um die Anzahl der Schemaversionen zu minimieren.
Auf Abschluss von API-Anfragen warten
Verwenden Sie beim Senden der Anfragen projects.instances.databases.updateDdl (REST API) oder UpdateDatabaseDdl (RPC API) jeweils projects.instances.databases.operations.get (REST API) oder GetOperation (RPC API), um auf den Abschluss der einzelnen Anfragen zu warten, bevor eine neue Anfrage gestartet wird. Ihre Anwendung kann dann den Fortschritt der Schemaaktualisierungen verfolgen. Außerdem bleibt der Rückstand von ausstehenden Schemaaktualisierungen in diesem Fall überschaubar.
Im Bulk laden
Wenn Sie Daten im Bulk in eine neue Tabelle laden, können Sie sekundäre Indexe vor oder nach dem Laden der Daten erstellen. Das Laden von Daten ist schneller, wenn Sie Indexe nach dem Laden erstellen. In diesem Fall müssen die Indexe jedoch mit vorhandenen Daten aufgefüllt werden.
Wenn Sie zuerst Daten laden und dann Indexe erstellen, ist die Datenaufnahme schneller, da nur in die Tabelle geschrieben wird. Bei den späteren Index-Backfills können die Indexdaten in optimierten Batches geschrieben werden, was effizienter ist als das Schreiben der Indexdaten zusammen mit den Tabellendaten. Für das Backfilling von Indexen sind jedoch mehrere Schemaversionen erforderlich und es gibt Einschränkungen. Wie unter Optionen für große Updates beschrieben, sollten Sie in einem einzelnen Batch nicht mehr als 10 Indexe erstellen, die Backfilling erfordern. Am besten erstellen Sie nicht mehr als 3 solche Indexe pro Tag.
Alternativ können Sie Tabellen und Indexe im selben Batch erstellen, wie unter Optionen für umfangreiche Aktualisierungen beschrieben. Dadurch wird das Auffüllen von Indexdaten vermieden, das Bulk-Laden von Daten ist jedoch langsamer, da jeder Index beim Laden von Daten aktualisiert werden muss.
Welche Option in einer bestimmten Situation besser ist, hängt davon ab, wie viele Daten geladen werden, von den spezifischen Tabellen- und Indexschlüsseln, wie viele Indexe benötigt werden und wie oft die Bulk-Ladevorgänge in derselben Datenbank erforderlich sind. Als Faustregel gilt, dass es besser ist, die Indexe separat zu erstellen, wenn eine große Menge an Daten in jede Tabelle geladen werden muss und nur wenige Indexe erforderlich sind.