Best Practices für die Datenbearbeitungssprache

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 umfassen, die die Filterbedingung der WHERE-Klausel nicht erfüllen.

Wenn Spanner Daten mithilfe von 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 ausgeführt werden.

Verwenden Sie eine WHERE-Klausel, mit der Spanner nur die erforderlichen Zeilen lesen kann, um Daten so effizient wie möglich zu ändern. 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 begrenzt den Umfang der gemeinsamen Sperren 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önnten die folgende DML-Anweisung ausführen, zwingt Spanner jedoch, die gesamte Tabelle zu scannen und erhält gemeinsame Sperren, 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 scannen, um die gewünschten Sänger zu finden. 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 dazu SELECT vor der Aktualisierungstransaktion in einer separaten schreibgeschützten Transaktion aus:


  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 innerhalb derselben Transaktion sichtbar. Dieses Verhalten unterscheidet sich von der Mutation API, bei der Spanner die Mutationen auf 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 im 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, empfiehlt es sich, DML-Anweisungen und -Mutationen in derselben Transaktion zu kombinieren, z. B. insert_or_update.

Wenn Sie beides verwenden, schreibt der Zwischenspeicher nur 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 zum Reduzieren der Latenz Batch-DML, um innerhalb eines einzigen Client-Server-Umlaufs mehrere DML-Anweisungen an Spanner zu senden.

Batch-DML kann Optimierungen auf Gruppen von Anweisungen in einem Batch 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, bei dem Sie eine große Menge neuer Zeilen in eine Tabelle namens Albums einfügen möchten. Damit Spanner alle erforderlichen INSERT-Anweisungen in einer einzigen, effizienten serverseitigen Aktion optimieren kann, müssen Sie zuerst eine entsprechende DML-Anweisung mit SQL-Abfrageparametern schreiben:

    INSERT INTO Albums (SingerId, AlbumId, AlbumTitle) VALUES (@Singer, @Album, @Title);
    

    Senden Sie Spanner dann 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 zusammenhängende Gruppen von DML-Anweisungen automatisch, indem es parallel ausgeführt wird, wenn dabei keine Datenabhängigkeiten verletzt werden. Diese Optimierung bietet Leistungsvorteile bei einer breiteren Reihe von Batch-DML-Anweisungen, da sie auf eine Mischung von DML-Anweisungstypen (INSERT, UPDATE und DELETE) und sowohl auf parametrisierte als auch nicht parametrierte DML-Anweisungen angewendet werden kann.

    Unser Beispielschema enthält beispielsweise die Tabellen Singers, Albums und Accounts. Albums ist mit Singers verschränkt und speichert Informationen zu Alben für Singers. Die folgende zusammenhängende Gruppe von Anweisungen schreibt neue Zeilen in mehrere Tabellen und weist keine komplexen Datenabhängigkeiten auf.

    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.