In diesem Dokument wird beschrieben, wie Sie für jeden Einfüge- und Aktualisierungsvorgang, den Sie mit Cloud Spanner ausführen, einen Commit-Zeitstempel schreiben. Damit Sie diese Funktion verwenden können, legen Sie für eine TIMESTAMP-Spalte die Option allow_commit_timestamp fest, und schreiben Sie dann den Zeitstempel als Teil jeder Transaktion.
Übersicht
Der Commit-Zeitstempel basiert auf der TrueTime-Technologie und ist der Zeitpunkt, zu dem in der Datenbank ein Commit für eine Transaktion durchgeführt wird. Mit der Spaltenoption allow_commit_timestamp können Sie den Commit-Zeitstempel in kleinstmöglicher Form in einer Spalte speichern.
Mit den in Tabellen gespeicherten Commit-Zeitstempeln können Sie die genaue Reihenfolge von Mutationen bestimmen und Elemente wie Änderungslogs erstellen.
Führen Sie die folgenden Schritte aus, um Commit-Zeitstempel in eine Datenbank einzufügen:
Erstellen Sie eine Spalte vom Typ
TIMESTAMP, wobei die Spaltenoptionallow_commit_timestampin der Schemadefinition auftruegesetzt ist. Beispiel:CREATE TABLE Performances ( ... LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true) ... ) PRIMARY KEY (...);Wenn Sie Einfügungen oder Aktualisierungen mit DML durchführen, verwenden Sie die Funktion
PENDING_COMMIT_TIMESTAMP, um den Commit-Zeitstempel zu schreiben.Wenn Sie Einfügungen oder Aktualisierungen mit Mutationen durchführen, verwenden Sie beim Einfügen oder Aktualisieren der Spalte mit den Commit-Zeitstempeln den Platzhalter-String
spanner.commit_timestamp(). Sie können auch die von der Clientbibliothek bereitgestellte Konstante für den Commit-Zeitstempel verwenden. Im Java-Client ist diese Konstante beispielsweiseValue.COMMIT_TIMESTAMP.
Wenn Cloud Spanner die Transaktion mit diesen Platzhaltern als Spaltenwerte festschreibt, wird der tatsächliche Commit-Zeitstempel in die angegebene Spalte geschrieben (z. B. die Spalte LastUpdateTime). Mit diesem Spaltenwert können Sie dann einen Verlauf der Aktualisierungen der Tabelle erstellen.
Die Werte der Commit-Zeitstempel sind nicht zwangsläufig eindeutig. Transaktionen, die in nicht überlappende Gruppen von Feldern schreiben, haben möglicherweise denselben Zeitstempel. Transaktionen, die in überlappende Gruppen von Feldern schreiben, haben eindeutige Zeitstempel.
Commit-Zeitstempel von Cloud Spanner haben eine Genauigkeit im Mikrosekundenbereich und werden beim Speichern in TIMESTAMP-Spalten in Nanosekunden umgewandelt.
Commit-Zeitstempelspalte erstellen und löschen
Verwenden Sie die Spaltenoption allow_commit_timestamp, um Unterstützung für Commit-Zeitstempel hinzuzufügen und zu entfernen:
- Beim Erstellen einer neuen Tabelle, um anzugeben, dass eine Spalte Commit-Zeitstempel unterstützt.
- Beim Ändern einer vorhandenen Tabelle:
- um eine neue Spalte hinzuzufügen, die Commit-Zeitstempel unterstützt,
- eine vorhandene
TIMESTAMP-Spalte ändern, um Commit-Zeitstempel zu unterstützen, - zum Ändern einer vorhandenen
TIMESTAMP-Spalte, um die Unterstützung von Commit-Zeitstempeln zu entfernen
Schlüssel und Indexe
Sie können eine Commit-Zeitstempelspalte als Primärschlüsselspalte oder als Nicht-Schlüsselspalte verwenden. Primärschlüssel können als ASC oder DESC definiert werden.
ASC(Standardeinstellung): Aufsteigende Schlüssel sind ideal für das Beantworten von Abfragen ab einem bestimmten Zeitpunkt.DESC: Bei absteigenden Schlüsseln bleiben die neuesten Zeilen oben in der Tabelle. Sie bieten schnellen Zugriff auf die neuesten Datensätze.
Die Option allow_commit_timestamp muss für die Primärschlüssel der über- und untergeordneten Tabellen konsistent sein. Wenn die Option für die Primärschlüssel nicht einheitlich festgelegt ist, gibt Spanner einen Fehler zurück. Die Option kann nur dann uneinheitlich festgelegt sein, wenn Sie das Schema erstellen oder aktualisieren.
Werden in den folgenden Szenarien Commit-Zeitstempel verwendet, entstehen Hotspots, wodurch die Datenleistung verringert wird:
Spalte der Commit-Zeitstempel als erster Teil des Primärschlüssels einer Tabelle:
CREATE TABLE Users ( LastAccess TIMESTAMP NOT NULL, UserId INT64 NOT NULL, ... ) PRIMARY KEY (LastAccess, UserId);Der erste Teil des Primärschlüssels eines Sekundärindex:
CREATE INDEX UsersByLastAccess ON Users(LastAccess)oder
CREATE INDEX UsersByLastAccessAndName ON Users(LastAccess, FirstName)
Hotspots verringern die Datenleistung selbst bei niedrigen Schreibraten. Wenn Commit-Zeitstempel für Nicht-Schlüsselspalten ohne Indexierung aktiviert sind, gibt es keine Leistungseinbußen.
Commit-Zeitstempelspalte erstellen
Die folgende DDL erstellt eine Tabelle mit einer Spalte, die Commit-Zeitstempel unterstützt.
CREATE TABLE Performances (
SingerId INT64 NOT NULL,
VenueId INT64 NOT NULL,
EventDate Date,
Revenue INT64,
LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (SingerId, VenueId, EventDate),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE
Durch Hinzufügen dieser Option ergeben sich für die Zeitstempelspalte folgende Änderungen:
- Sie können den Platzhalterstring
spanner.commit_timestamp()bzw. eine Konstante, die von der Clientbibliothek bereitgestellt wird, für Einfügungen und Aktualisierungen verwenden. - Die Spalte darf nur Werte enthalten, die in der Vergangenheit liegen. Weitere Informationen finden Sie unter Bereitstellen eines eigenen Wertes für den Zeitstempel.
Bei der Option allow_commit_timestamp wird zwischen Groß- und Kleinschreibung unterschieden.
Zeitstempelspalte in eine vorhandene Tabelle aufnehmen
Verwenden Sie die Anweisung ALTER TABLE, um einer vorhandenen Tabelle eine Commit-Zeitstempelspalte hinzuzufügen. Geben Sie beispielsweise die folgende Anweisung ein, um der Tabelle Performances die Spalte LastUpdateTime hinzuzufügen:
ALTER TABLE Performances ADD COLUMN LastUpdateTime TIMESTAMP
NOT NULL OPTIONS (allow_commit_timestamp=true)
Zeitstempelspalte in eine Commit-Zeitstempelspalte konvertieren
Sie können eine vorhandene Zeitstempelspalte in eine Commit-Zeitstempelspalte konvertieren. Dazu muss Spanner jedoch überprüfen, dass die vorhandenen Zeitstempelwerte in der Vergangenheit liegen. Beispiel:
ALTER TABLE Performances ALTER COLUMN LastUpdateTime
SET OPTIONS (allow_commit_timestamp=true)
In einer ALTER TABLE-Anweisung, die SET OPTIONS enthält, können Sie den Datentyp bzw. die NULL-Anmerkung einer Spalte nicht ändern. Weitere Informationen finden Sie unter Datendefinitionssprache.
Commit-Zeitstempeloption entfernen
Wenn Sie die Unterstützung für Commit-Zeitstempel aus einer Spalte entfernen möchten, verwenden Sie die Option allow_commit_timestamp=null in einer ALTER TABLE-Anweisung. Das Verhalten für Commit-Zeitstempel wird entfernt, aber die Spalte bleibt weiterhin ein Zeitstempel. Durch die Änderung der Option verändern sich keine anderen Eigenschaften der Spalte, wie Typ oder Unwirksamkeit (NOT NULL). Beispiel:
ALTER TABLE Performances ALTER COLUMN LastUpdateTime
SET OPTIONS (allow_commit_timestamp=null)
Commit-Zeitstempel mit einer DML-Anweisung schreiben
Sie verwenden Sie Funktion PENDING_COMMIT_TIMESTAMP, um den Commit-Zeitstempel in eine DML-Anweisung zu schreiben. Cloud Spanner wählt den Commit-Zeitstempel aus, wenn der Commit der Transaktion durchgeführt wird.
Mit der folgenden DML-Anweisung wird die Spalte LastUpdateTime der Tabelle Performances mit dem Commit-Zeitstempel aktualisiert.
UPDATE Performances SET LastUpdateTime = PENDING_COMMIT_TIMESTAMP()
WHERE SingerId=1 AND VenueId=2 AND EventDate="2015-10-21"
Im folgenden Codebeispiel wird die Funktion PENDING_COMMIT_TIMESTAMP zum Schreiben des Commit-Zeitstempels in die Spalte LastUpdateTime verwendet.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Ruby
Commit-Zeitstempel können nur in Spalten geschrieben werden, die mit der Option allow_commit_timestamp=true gekennzeichnet sind.
Wenn Sie Mutationen in Zeilen in mehreren Tabellen haben, müssen Sie spanner.commit_timestamp() bzw. die Konstante der Clientbibliothek für die Commit-Zeitstempelspalte in jeder Tabelle angeben.
Commit-Zeitstempelspalte abfragen
Im folgenden Beispiel wird die Commit-Zeitstempelspalte der Tabelle abgefragt.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Eigenen Wert für die Commit-Zeitstempelspalte angeben
Sie können Ihren eigenen Wert für die Commit-Zeitstempelspalte verwenden, anstatt spanner.commit_timestamp() bzw. die Konstante der Clientbilbiothek als Spaltenwert zu übergeben. Der Wert muss ein Zeitstempel sein, der in der Vergangenheit liegt. Mit dieser Einschränkung wird sichergestellt, dass das Schreiben von Zeitstempeln ein kostengünstiger und schneller Vorgang ist. Der Server gibt den Fehler FailedPrecondition zurück, wenn ein zukünftiger Zeitstempel angegeben ist.
Änderungslog erstellen
Angenommen, Sie möchten ein Änderungslog aller Mutationen erstellen, die an einer Tabelle vorgenommen werden, und dieses Änderungslog dann für Audits verwenden. Ein Beispiel wäre eine Tabelle, in der der Änderungsverlauf von Textverarbeitungsdokumenten gespeichert wird. Der Commit-Zeitstempel erleichtert das Erstellen des Änderungslogs, da die entsprechende Reihenfolge der Einträge im Änderungslog durch die Zeitstempel erzwungen werden kann. Sie könnten ein Änderungslog mit dem Änderungsverlauf eines bestimmten Dokuments erstellen, indem Sie ein Schema wie im folgenden Beispiel verwenden:
CREATE TABLE Documents (
UserId INT64 NOT NULL,
DocumentId INT64 NOT NULL,
Contents STRING(MAX) NOT NULL,
) PRIMARY KEY (UserId, DocumentId);
CREATE TABLE DocumentHistory (
UserId INT64 NOT NULL,
DocumentId INT64 NOT NULL,
Ts TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
Delta STRING(MAX),
) PRIMARY KEY (UserId, DocumentId, Ts),
INTERLEAVE IN PARENT Documents ON DELETE NO ACTION;
Zum Erstellen eines Änderungslogs fügen Sie in derselben Transaktion, in der Sie eine Zeile in Document einfügen oder aktualisieren, eine neue Zeile in DocumentHistory ein. Verwenden Sie beim Einfügen der neuen Zeile in DocumentHistory den Platzhalter spanner.commit_timestamp() bzw. die Konstante der Clientbibliothek, damit Cloud Spanner den Commit-Zeitstempel in die Spalte Ts schreibt. Das Verschränken der Tabelle DocumentsHistory mit der Tabelle Documents sorgt für Datenlokalität und effizientere Einfüge- und Aktualisierungsvorgänge. Dadurch ergibt sich jedoch auch die zusätzliche Einschränkung, dass die übergeordneten und untergeordneten Zeilen zusammen gelöscht werden müssen. Sie sollten die Tabellen nicht verschränken, damit die Zeilen in DocumentHistory beibehalten werden, nachdem Zeilen in Documents gelöscht wurden.
Abfragen aktueller Daten mit Commit-Zeitstempeln optimieren
Commit-Zeitstempel ermöglichen eine Spanner-Optimierung, die die Abfrage-E/A beim Abrufen von Daten reduzieren kann, die nach einem bestimmten Zeitpunkt geschrieben wurden.
Für diese Optimierung muss die Anweisung WHERE einer Abfrage einen Vergleich zwischen der Commit-Zeitstempelspalte einer Tabelle und einem von Ihnen angegebenen Zeitpunkt mit folgenden Attributen enthalten:
Geben Sie die genaue Zeit als konstanten Ausdruck an: ein Literal, ein Parameter oder eine Funktion, deren eigene Argumente als Konstanten ausgewertet werden.
Vergleichen Sie, ob der Commit-Zeitstempel neuer als die angegebene Zeit ist. Verwenden Sie dazu entweder den Operator
>oder>=.Optional können Sie der Anweisung
WHEREmitANDweitere Einschränkungen hinzufügen. Wenn Sie die Anweisung mitORerweitern, wird die Abfrage von dieser Optimierung ausgeschlossen.
Sehen Sie sich beispielsweise die folgende Tabelle Performances mit einer Commit-Zeitstempelspalte an:
CREATE TABLE Performances (
SingerId INT64 NOT NULL,
VenueId INT64 NOT NULL,
EventDate DATE,
Revenue INT64,
LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (SingerId, VenueId, EventDate);
Diese Abfrage profitiert von der oben beschriebenen Optimierung durch Commit-Zeitstempel, da sie einen „Größer als oder gleich“-Vergleich zwischen der Commit-Zeitstempelspalte der Tabelle und einem konstanten Ausdruck enthält – in diesem Fall ein Literal:
SELECT * FROM Performances WHERE LastUpdateTime >= "2022-05-01";
Die folgende Abfrage kommt ebenfalls für die Optimierung infrage, da sie einen „Größer als“-Vergleich zwischen dem Commit-Zeitstempel und einer Funktion enthält, deren Argumente während der Ausführung der Abfrage alle als Konstanten ausgewertet werden:
SELECT * FROM Performances
WHERE LastUpdateTime > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY);
Nächste Schritte
- Mit Commit-Zeitstempeln ein Änderungslog mit Go erstellen.