In diesem Thema wird beschrieben, wie Sie einen Commit-Zeitstempel für jeden Einfüge- und Aktualisierungsvorgang schreiben, den Sie mit Spanner ausführen.
Commit-Zeitstempel – Übersicht
Der Commit-Zeitstempel basierend auf der TrueTime-Technologie ist der Zeitpunkt, zu dem eine Transaktion in der Datenbank per Commit festgeschrieben wird. Sie können den Commit-Zeitstempel einer Transaktion atomar 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
SPANNER.COMMIT_TIMESTAMP
. Beispiel:CREATE TABLE Performances ( ... LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL, ... PRIMARY KEY (...) ) ;
Wenn Sie Einfügungen oder Aktualisierungen mit DML durchführen, verwenden Sie die Funktion
SPANNER.PENDING_COMMIT_TIMESTAMP()
, um den Commit-Zeitstempel zu schreiben.Wenn Sie Einfügungen oder Aktualisierungen mit vorbereiteten Anweisungen oder Mutationen durchführen, verwenden Sie den Platzhalterstring
SPANNER.COMMIT_TIMESTAMP()
für die Commit-Zeitstempelspalte. Sie können auch die von der Clientbibliothek bereitgestellte Commit-Zeitstempelkonstante verwenden. Diese Konstante im Java-Client ist beispielsweiseValue.COMMIT_TIMESTAMP
.
Wenn Spanner die Transaktion mithilfe dieser Platzhalter als Spaltenwerte mit Commit ausführt, wird der tatsächliche Commit-Zeitstempel in die angegebene Spalte geschrieben. Anschließend können Sie mit diesem Spaltenwert einen Verlauf der Aktualisierungen der Tabelle erstellen.
Die Werte der Commit-Zeitstempel sind nicht zwangsläufig eindeutig. Transaktionen, bei denen in nicht überlappende Gruppen von Feldern geschrieben wird, haben möglicherweise den gleichen Zeitstempel. Transaktionen, bei denen in überlappende Gruppen von Feldern geschrieben wird, haben eindeutige Zeitstempel.
Spanner-Commit-Zeitstempel haben einen Detaillierungsgrad auf Mikrosekunden und werden beim Speichern in SPANNER.COMMIT_TIMESTAMP
-Spalten in Nanosekunden umgewandelt.
Schlüssel und Indexe
Sie können eine Commit-Zeitstempelspalte als Primärschlüsselspalte oder als Spalte verwenden, die keine Schlüsselspalte ist. Primärschlüssel können als ASC
oder DESC
definiert werden.
ASC
(Standard): Aufsteigende Schlüssel sind ideal für die Beantwortung von Abfragen ab einem bestimmten Zeitpunkt.DESC
: Bei absteigenden Schlüsseln werden die neuesten Zeilen am Tabellenanfang gespeichert. Sie bieten schnellen Zugriff auf die neuesten Datensätze.
Hotspots vermeiden
Die Verwendung von Commit-Zeitstempeln in den folgenden Szenarien führt zu Hotspots, was die Datenleistung verringert:
Spalte mit Commit-Zeitstempel als erster Teil des Primärschlüssels einer Tabelle.
CREATE TABLE Users ( LastAccess SPANNER.COMMIT_TIMESTAMP NOT NULL, UserId INT64 NOT NULL, ... PRIMARY KEY (LastAccess, UserId) ) ;
Primärschlüsselspalte für Commit-Zeitstempel als erster Teil eines sekundären Index.
CREATE INDEX UsersByLastAccess ON Users(LastAccess)
oder
CREATE INDEX UsersByLastAccessAndName ON Users(LastAccess, FirstName)
Hotspots verringern die Datenleistung auch bei niedrigen Schreibraten. Wenn Commit-Zeitstempel für Nicht-Schlüsselspalten ohne Indexierung aktiviert sind, gibt es keine Leistungseinbußen.
Einer vorhandenen Tabelle eine Commit-Zeitstempelspalte hinzufügen
Verwenden Sie die Anweisung ALTER TABLE
, um einer vorhandenen Tabelle eine Commit-Zeitstempelspalte hinzuzufügen: Verwenden Sie beispielsweise die folgende Anweisung, um der Tabelle Performances
eine Spalte LastUpdateTime
hinzuzufügen:
ALTER TABLE Performances ADD COLUMN LastUpdateTime SPANNER.COMMIT_TIMESTAMP
NOT NULL;
Commit-Zeitstempel mit einer DML-Anweisung schreiben
Schreiben Sie mit der Funktion SPANNER.PENDING_COMMIT_TIMESTAMP()
den Commit-Zeitstempel in eine DML-Anweisung. Spanner wählt den Commit-Zeitstempel aus, wenn der Commit der Transaktion durchgeführt wird.
Mit der folgenden DML-Anweisung wird der Commit-Zeitstempel in die Spalte LastUpdateTime
in der Tabelle Performances
geschrieben.
UPDATE Performances SET LastUpdateTime = SPANNER.PENDING_COMMIT_TIMESTAMP()
WHERE SingerId=1 AND VenueId=2 AND EventDate="2015-10-21"
Zeile mit einer Mutation einfügen
Beim Einfügen einer Zeile schreibt Spanner den Wert für den Commit-Zeitstempel nur, wenn die Spalte in der Spaltenliste enthalten ist und der Platzhalterstring spanner.commit_timestamp()
(oder die Konstante der Clientbibliothek) als Wert übergeben wird. Beispiel:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
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.
Zeile mit einer Mutation aktualisieren
Beim Aktualisieren einer Zeile schreibt Spanner den Wert für den Commit-Zeitstempel nur, wenn die Spalte in der Spaltenliste enthalten ist und der Platzhalterstring spanner.commit_timestamp()
(oder die Konstante der Clientbibliothek) als Wert übergeben wird. Der Primärschlüssel einer Zeile kann nicht aktualisiert werden. Sie müssen die vorhandene Zeile löschen und eine neue Zeile erstellen, um den Primärschlüssel zu aktualisieren.
Die Commit-Zeitstempelspalte mit dem Namen LastUpdateTime
können Sie beispielsweise so aktualisieren:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
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.
Spalte mit Commit-Zeitstempel abfragen
Im folgenden Beispiel wird die Commit-Zeitstempelspalte der Tabelle abgefragt.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Geben Sie einen eigenen Wert für die Commit-Zeitstempelspalte ein
Sie können in Ihrem Code einen eigenen Wert für die Commit-Zeitstempelspalte angeben, anstatt spanner.commit_timestamp()
(oder die verfügbare Konstante der Clientbibliothek) 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. Eine einfache Möglichkeit, um zu bestätigen, dass ein Wert in der Vergangenheit liegt, besteht darin, ihn mit dem von der SQL-Funktion CURRENT_TIMESTAMP
zurückgegebenen Wert zu vergleichen.
Der Server gibt den Fehler FailedPrecondition
zurück, wenn ein Zeitstempel angegeben ist, der in der Zukunft liegt.
Änderungsprotokoll erstellen
Angenommen, Sie möchten für jede an einer Tabelle vorgenommene Mutation ein Änderungslog erstellen und dieses Änderungslog dann zur Überprüfung verwenden. Ein Beispiel wäre eine Tabelle, in der der Änderungsverlauf von Textverarbeitungsdokumenten gespeichert wird. Der Commit-Zeitstempel erleichtert das Erstellen des Änderungslogs, weil die Einträge im Änderungslog aufgrund der Zeitstempel in die entsprechende Reihenfolge gebracht werden können. Sie könnten ein Änderungslog erstellen, in dem der Verlauf der Änderungen an einem bestimmten Dokument gespeichert wird, indem Sie ein Schema wie in folgendem Beispiel verwenden:
CREATE TABLE Documents (
UserId int8 NOT NULL,
DocumentId int8 NOT NULL,
Contents text NOT NULL,
PRIMARY KEY (UserId, DocumentId)
);
CREATE TABLE DocumentHistory (
UserId int8 NOT NULL,
DocumentId int8 NOT NULL,
Ts SPANNER.COMMIT_TIMESTAMP NOT NULL,
Delta text,
PRIMARY KEY (UserId, DocumentId, Ts)
) INTERLEAVE IN PARENT Documents;
Wenn Sie ein Änderungslog erstellen möchten, fügen Sie in derselben Transaktion, in die 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()
(oder die Konstante der Clientbibliothek), damit Spanner den Commit-Zeitstempel in die Spalte Ts
schreiben soll. 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.
Letzte Datenabfragen mit Commit-Zeitstempeln optimieren
Commit-Zeitstempel ermöglichen eine Spanner-Optimierung, die die E/A-Abfrage von Abfragen reduzieren kann, wenn Daten abgerufen werden, die nach einer bestimmten Zeit geschrieben wurden.
Zum Aktivieren dieser Optimierung muss die WHERE
-Klausel einer Abfrage einen Vergleich zwischen der Commit-Zeitstempelspalte einer Tabelle und einer von Ihnen angegebenen Zeit mit den folgenden Attributen enthalten:
Geben Sie die bestimmte 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 nach der angegebenen Zeit liegt. Verwenden Sie dazu entweder den Operator
>
oder>=
.Optional können Sie mit
AND
weitere Einschränkungen zurWHERE
-Klausel hinzufügen. Durch das Erweitern der Klausel mitOR
wird die Abfrage von dieser Optimierung ausgeschlossen.
Betrachten Sie beispielsweise die folgende Performances
-Tabelle, die eine Commit-Zeitstempelspalte enthält:
CREATE TABLE Performances (
SingerId bigint NOT NULL,
VenueId bigint NOT NULL,
EventDate timestamp with time zone NOT NULL,
Revenue bigint,
LastUpdateTime spanner.commit_timestamp,
PRIMARY KEY(SingerId, VenueId, EventDate)
);
Diese Abfrage profitiert von der zuvor beschriebenen Commit-Zeitstempeloptimierung, da sie einen größeren-als-oder-gleich-zu-Vergleich zwischen der Commit-Zeitstempelspalte der Tabelle und einem konstanten Ausdruck – in diesem Fall ein Literal – hat:
SELECT * FROM Performances WHERE LastUpdateTime >= '2022-01-01';