DML und Mutationen vergleichen

Datenbearbeitungssprache (DML) und Mutations sind zwei APIs in Cloud Spanner, mit denen Sie Daten ändern können. Sie bieten ähnliche Features zur Datenbearbeitung. Auf dieser Seite werden die Ansätze verglichen.

Was ist die Datenbearbeitungssprache (DML, Data Manipulation Language)?

Mit der Datenbearbeitungssprache (Data Manipulation Language, DML) in Cloud Spanner können Sie Daten in Ihren Datenbanktabellen mit INSERT-, UPDATE- und DELETE-Anweisungen bearbeiten. Sie können DML-Anweisungen mit Clientbibliotheken, Cloud Console und Gcloud Spanner ausführen.

Cloud Spanner bietet folgende zwei Implementierungen der DML-Ausführung mit jeweils unterschiedlichen Attributen.

  • Standard-DML: Geeignet für standardmäßige OLTP-Arbeitslasten (Online Transaction Processing).

    Weitere Informationen und Codebeispiele finden sich unter DML verwenden.

  • Partitionierte DML: Wurde für Bulk-Aktualisierungen und -Löschvorgänge konzipiert, wie in folgenden Beispielen beschrieben.

    • Regelmäßige und automatische Speicherbereinigungsvorgänge. Beispiele: Alte Zeilen löschen oder Spalten auf NULL setzen.

    • Backfilling neuer Spalten mit Standardwerten. Beispiel: Mit einer UPDATE-Anweisung können Sie für den Wert einer neuen Spalte False festlegen, für die aktuell NULL gilt.

    Weitere Informationen und Codebeispiele finden sich unter Partitionierte DML verwenden.

Was sind Mutationen?

Eine Mutation stellt eine Folge von Einfügungs-, Aktualisierungs- und Löschvorgängen dar, die Cloud Spanner in kleinstmöglichen Schritten auf verschiedene Zeilen und Tabellen in einer Datenbank anwendet. Sie können Vorgänge aufnehmen, die auf verschiedene Zeilen oder Tabellen in einer Mutation angewendet werden. Nachdem Sie eine oder mehrere Mutationen definiert haben, die je einen oder mehrere Schreibvorgänge enthalten, müssen Sie die Mutation anwenden, um einen Commit für die Schreibvorgänge auszuführen. Änderungen werden in der Reihenfolge angewendet, in der sie der Mutation hinzugefügt wurden.

Weitere Informationen und Codebeispiele finden Sie unter Daten mit Mutationen einfügen, aktualisieren und löschen.

Featurevergleich zwischen DML und Mutationen

In folgender Tabelle sind DML- und Mutationsunterstützung für häufige Datenbankoperationen und -funktionen zusammengefasst.

Vorgänge DML Mutationen
Daten einfügen Unterstützt Unterstützt
Daten löschen Unterstützt Unterstützt
Daten aktualisieren Unterstützt Unterstützt
Schreibvorgänge lesen (RYW, Read Your Writes) Unterstützt Nicht unterstützt
Upsert (einfügen oder aktualisieren) Nicht unterstützt Unterstützt
SQL-Syntax Unterstützt Nicht unterstützt
Einschränkung prüfen Nach jeder Anweisung Beim Commit

DML und Mutationen weichen in ihrer Unterstützung folgender Features ab.

  • Read Your Writes-Semantics: Mit "Read Your Writes" können Sie nicht übergebene Ergebnisse in aktiven Transaktionen lesen. Änderungen, die Sie innerhalb von DML-Anweisungen vornehmen, sind für nachfolgende Anweisungen in derselben Transaktion sichtbar. Dies unterscheidet sich von Mutationen, bei denen Änderungen in Lesevorgängen (einschließlich Lesevorgängen in derselben Transaktion) erst beim Commit der Transaktion sichtbar werden. Grund dafür ist, dass Mutationen in einer Transaktion clientseitig (lokal) gepuffert und als Teil des Commit-Vorgangs an den Server gesendet werden. Folglich sind Mutationen in der Commit-Anfrage für SQL- oder DML-Anweisungen in derselben Transaktion nicht sichtbar.

  • Upsert: DML unterstützt das native Upsert nicht. Bei diesem Vorgang werden Zeilen in eine Datenbanktabelle eingefügt, falls sie noch nicht vorhanden sind; existieren sie, so werden sie aktualisiert. Es gibt jedoch einen insert_or_update-Vorgang in der Mutationsumgebung. Anwendungen, die DML verwenden, können diese Einschränkung umgehen. Dazu lesen sie zuerst die Zeile und dann die entsprechende DML-Anweisung.

  • Einschränkungen prüfen: Cloud Spanner prüft nach jeder DML-Anweisung auf Einschränkungen. Dies unterscheidet sich von der Verwendung von Mutationen, bei denen Cloud Spanner die Mutationen im Client bis zum Commit puffert und Einschränkungen erst beim Commit geprüft werden. Durch Auswertung der Einschränkungen nach jeder DML-Anweisung stellt Cloud Spanner sicher, dass die Daten, die von einer nachfolgenden Abfrage in derselben Transaktion zurückgegeben werden, mit dem Schema konsistent sind.

  • SQL-Syntax: DML bietet eine herkömmliche Methode zum Bearbeiten von Daten. Sie können SQL-Kompetenzen nutzen, um die Daten mit der DML API zu ändern.

Best Practice: Kombinieren Sie DML und Mutationen nicht in derselben Transaktion

Wenn eine Transaktion sowohl DML-Anweisungen als auch Mutationen in der Commit-Anfrage enthält, führt Cloud Spanner die DML-Anweisungen vor den Mutationen aus. Sie sollten entweder DML-Anweisungen oder Mutationen in einer einzelnen Transaktion verwenden, nicht jedoch beide, damit Sie die Reihenfolge der Ausführung in Ihrem Client-Bibliothekscode nicht berücksichtigen müssen.

Folgendes Java-Beispiel veranschaulicht ein potenziell überraschendes Verhalten. Der Code fügt per Mutation API zwei Zeilen in Alben ein. Das Snippet ruft dann executeUpdate() auf, um die neu eingefügten Zeilen zu aktualisieren und executeQuery() aufzurufen, um die aktualisierten Alben zu lesen.

static void updateMarketingBudget(DatabaseClient dbClient) {
  dbClient
      .readWriteTransaction()
      .run(
          new TransactionCallable<Void>() {
            @Override
            public Void run(TransactionContext transaction) throws Exception {
               transaction.buffer(
                    Mutation.newInsertBuilder("Albums")
                        .set("SingerId")
                        .to(1)
                        .set("AlbumId")
                        .to(1)
                        .set("AlbumTitle")
                        .to("Total Junk")
                        .set("MarketingBudget")
                        .to(800)
                        .build());
               transaction.buffer(
                    Mutation.newInsertBuilder("Albums")
                        .set("SingerId")
                        .to(1)
                        .set("AlbumId")
                        .to(2)
                        .set("AlbumTitle")
                        .to("Go Go Go")
                        .set("MarketingBudget")
                        .to(200)
                        .build());

                // This UPDATE will not include the Albums inserted above.
                String sql =
                  "UPDATE Albums SET MarketingBudget = MarketingBudget * 2"
                      + " WHERE SingerId = 1";
                long rowCount = transaction.executeUpdate(Statement.of(sql));
                System.out.printf("%d records updated.\n", rowCount);

                // Read a newly updated record.
                sql =
                  "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"
                      + " WHERE SingerId = 1 AND MarketingBudget < 1000";
                ResultSet resultSet =
                                 transaction.executeQuery(Statement.of(sql));
                while (resultSet.next()) {
                   System.out.printf(
                        "%s %s\n",
                        resultSet.getString("FirstName"),
                        resultSet.getString("LastName"));
                }
                return null;
              }
            });
}

Bei der Ausführung dieses Codes würde 0 Datensätze aktualisiert angezeigt. Warum? Grund ist, dass die mit Mutationen vorgenommenen Änderungen für nachfolgende Anweisungen erst nach dem Commit der Transaktion sichtbar sind. Idealerweise sollten am Ende der Transaktion nur noch gepufferte Schreibvorgänge existieren.

Nächste Schritte