Auf dieser Seite werden die Best Practices für die Verwendung der Datenbearbeitungssprache (Data Manipulation Language – DML) und der partitionierten DML beschrieben.
Mit einer WHERE-Klausel die Anzahl der gesperrten Zeilen reduzieren
Sie führen DML-Anweisungen in Lese- und Schreibtransaktionen aus. Wenn Spanner Daten liest, werden gemeinsame Lesesperren für begrenzte Teile der gelesenen Zeilenbereiche übernommen. Insbesondere werden diese Sperren nur für die Spalten übernommen, auf die Sie zugreifen. Die Sperren können Daten enthalten, die die Filterbedingung der WHERE
-Klausel nicht erfüllen.
Wenn Spanner Daten mit DML-Anweisungen ändert, werden exklusive Sperren für die Daten übernommen, die Sie ändern. Darüber hinaus werden gemeinsame Sperren auf die gleiche Weise wie beim Lesen von Daten angewendet. Wenn Ihre Anfrage große Zeilenbereiche oder eine ganze Tabelle enthält, verhindern die gemeinsamen Sperren möglicherweise, dass andere Transaktionen parallel weiterarbeiten.
Um Daten so effizient wie möglich zu ändern, verwenden Sie die WHERE
-Klausel, die es Spanner ermöglicht, nur die erforderlichen Zeilen zu lesen. Sie können dafür einen Filter für den Primärschlüssel oder für den Schlüssel eines Sekundärindex nutzen. Die WHERE
-Klausel schränkt den Umfang der gemeinsamen Sperren ein und ermöglicht Spanner, die Aktualisierung effizienter zu verarbeiten.
Angenommen, einer der Musiker in der Tabelle Singers
ändert seinen Vornamen und Sie müssen den Namen in Ihrer Datenbank aktualisieren. Sie können die folgende DML-Anweisung ausführen. Spanner wird jedoch gezwungen, die gesamte Tabelle zu scannen und gemeinsame Sperren abzurufen, die die gesamte Tabelle abdecken. Daher muss Spanner mehr Daten als nötig lesen und gleichzeitige Transaktionen können die Daten nicht parallel ändern:
-- ANTI-PATTERN: SENDING AN UPDATE WITHOUT THE PRIMARY KEY COLUMN
-- IN THE WHERE CLAUSE
UPDATE Singers SET FirstName = "Marcel"
WHERE FirstName = "Marc" AND LastName = "Richards";
Für eine effizientere Aktualisierung nehmen Sie die Spalte SingerId
in die WHERE
-Klausel auf. Die Spalte SingerId
ist die einzige primäre Schlüsselspalte für die Tabelle Singers
:
-- ANTI-PATTERN: SENDING AN UPDATE THAT MUST SCAN THE ENTIRE TABLE
UPDATE Singers SET FirstName = "Marcel"
WHERE FirstName = "Marc" AND LastName = "Richards"
Wenn für FirstName
oder LastName
kein Index vorhanden ist, müssen Sie die gesamte Tabelle nach den Zielsingern durchsuchen. Wenn Sie keinen sekundären Index hinzufügen möchten, um die Aktualisierung effizienter zu machen, fügen Sie die Spalte SingerId
in die WHERE
-Klausel ein.
Die Spalte SingerId
ist die einzige Primärschlüsselspalte für die Tabelle Singers
. Führen Sie SELECT
vor der Aktualisierungstransaktion in einer separaten, schreibgeschützten Transaktion aus, um sie zu ermitteln:
SELECT SingerId
FROM Singers
WHERE FirstName = "Marc" AND LastName = "Richards"
-- Recommended: Including a seekable filter in the where clause
UPDATE Singers SET FirstName = "Marcel"
WHERE SingerId = 1;
Vermeiden Sie die Verwendung von DML-Anweisungen und -Mutationen in derselben Transaktion
Spanner speichert Einfügungen, Aktualisierungen und Löschungen, die mit DML-Anweisungen auf der Serverseite ausgeführt wurden, im Zwischenspeicher. Die Ergebnisse sind für nachfolgende SQL- und DML-Anweisungen in derselben Transaktion sichtbar. Dieses Verhalten unterscheidet sich von der Mutation API, bei der Spanner die Mutationen auf der Clientseite zwischenspeichert und sie serverseitig als Teil des Commit-Vorgangs sendet. Folglich sind Mutationen in der Commit-Anfrage für SQL- oder DML-Anweisungen in derselben Transaktion nicht sichtbar.
Vermeiden Sie die Verwendung von DML-Anweisungen und Mutationen in derselben Transaktion. Wenn Sie beide in derselben Transaktion verwenden, müssen Sie die Reihenfolge der Ausführung in Ihrem Clientbibliothekscode berücksichtigen. Wenn eine Transaktion sowohl DML-Anweisungen als auch Mutationen in derselben Anfrage enthält, führt Spanner die DML-Anweisungen vor den Mutationen aus.
Bei Vorgängen, die nur mit Mutationen unterstützt werden, können Sie DML-Anweisungen und Mutationen in derselben Transaktion kombinieren, z. B. insert_or_update
.
Wenn Sie beide verwenden, schreibt der Zwischenspeicher nur ganz am Ende der Transaktion.
Mit der Funktion PENDING_COMMIT_TIMESTAMP um Commit-Zeitstempel schreiben
GoogleSQL
Schreiben Sie mit der Funktion 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.
PostgreSQL
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.
Partitionierte DML-, Datums- und Zeitstempelfunktionen
Partitionierte DML verwendet eine oder mehrere Transaktionen, die möglicherweise zu unterschiedlichen Zeitpunkten ausgeführt und bereitgestellt werden. Wenn Sie die Datums- oder Zeitstempelfunktion verwenden, können die geänderten Zeilen andere Werte enthalten.
Latenz mit Batch-DML verbessern
Verwenden Sie Batch-DML, um innerhalb eines einzelnen Client-Server-Roundtrips mehrere DML-Anweisungen an Spanner zu senden, um die Latenz zu verringern.
Batch-DML kann Optimierungen auf Gruppen von Anweisungen innerhalb eines Batches anwenden, um schnellere und effizientere Datenaktualisierungen zu ermöglichen.
Schreibvorgänge mit einer einzigen Anfrage ausführen
Spanner optimiert automatisch zusammenhängende Gruppen ähnlicher INSERT-, UPDATE- oder DELETE-Batchanweisungen mit unterschiedlichen Parameterwerten, wenn sie nicht gegen Datenabhängigkeiten verstoßen.
Stellen Sie sich beispielsweise ein Szenario vor, in dem Sie eine große Menge neuer Zeilen in eine Tabelle mit dem Namen
Albums
einfügen möchten. Damit Spanner alle erforderlichenINSERT
-Anweisungen in einer einzigen, effizienten serverseitigen Aktion optimieren kann, müssen Sie zuerst eine entsprechende DML-Anweisung schreiben, die SQL-Abfrageparameter verwendet:INSERT INTO Albums (SingerId, AlbumId, AlbumTitle) VALUES (@Singer, @Album, @Title);
Senden Sie dann Spanner einen DML-Batch, der diese Anweisung wiederholt und fortlaufend aufruft, wobei sich die Wiederholungen nur in den Werten unterscheiden, die Sie an die drei Abfrageparameter der Anweisung binden. Spanner optimiert diese strukturell identischen DML-Anweisungen vor der Ausführung in einem einzigen serverseitigen Vorgang.
Schreibvorgänge parallel ausführen
Spanner optimiert automatisch zusammenhängende Gruppen von DML-Anweisungen, indem es parallel ausgeführt wird, wenn dies nicht gegen Datenabhängigkeiten verstößt. Diese Optimierung bietet einem breiteren Satz von DML-Batch-Anweisungen Leistungsvorteile, da sie sich auf eine Mischung aus DML-Anweisungstypen (INSERT, UPDATE und DELETE) und sowohl auf parametrisierte als auch nicht parametrisierte DML-Anweisungen anwenden können.
Unser Beispielschema enthält beispielsweise die Tabellen
Singers
,Albums
undAccounts
.Albums
ist mitSingers
verschränkt und speichert Informationen zu Alben fürSingers
. Die folgende zusammenhängende Gruppe von Anweisungen schreibt neue Zeilen in mehrere Tabellen und hat keine komplexen Datenabhängigkeiten.INSERT INTO Singers (SingerId, Name) VALUES(1, "John Doe"); INSERT INTO Singers (SingerId, Name) VALUES(2, "Marcel Richards"); INSERT INTO Albums(SingerId, AlbumId, AlbumTitle) VALUES (1, 10001, "Album 1"); INSERT INTO Albums(SingerId, AlbumId, AlbumTitle) VALUES (1, 10002, "Album 2"); INSERT INTO Albums(SingerId, AlbumId, AlbumTitle) VALUES (2, 10001, "Album 1"); UPDATE Accounts SET Balance = 100 WHERE AccountId = @AccountId;
Spanner optimiert diese Gruppe von DML-Anweisungen, indem die Anweisungen parallel ausgeführt werden. Die Schreibvorgänge werden in der Reihenfolge der Anweisungen im Batch angewendet und behält die Batch-DML-Semantik bei, wenn eine Anweisung während der Ausführung fehlschlägt.