Comparer le LMD et les mutations

Le langage de manipulation de données (LMD) et les mutations sont deux API de Spanner que vous pouvez utiliser pour modifier des données. Chacun offre des fonctionnalités de manipulation de données similaires. Cette page compare les deux approches.

Qu'est-ce que le langage de manipulation de données (LMD) ?

Le langage de manipulation de données (LMD) de Spanner vous permet de manipuler les données de vos tables de base de données à l'aide des instructions INSERT, UPDATE et DELETE. Vous pouvez exécuter des instructions LMD à l'aide des bibliothèques clientes, de la consoleGoogle Cloud et de gcloud spanner.

Spanner propose les deux implémentations d'exécution LMD suivantes, chacune avec des propriétés différentes.

  • LMD standard : adapté aux charges de travail OLTP (Online Transaction Processing) standards.

    Pour en savoir plus et obtenir des exemples de code, consultez la section Utiliser le LMD.

  • LMD partitionné : conçu pour les mises à jour et les suppressions de manière groupée, comme dans les exemples suivants.

    • Nettoyage périodique et récupération de mémoire. Il s'agit par exemple de supprimer d'anciennes lignes ou de définir des colonnes sur NULL.

    • Remplissage de nouvelles colonnes avec des valeurs par défaut. Par exemple, vous pouvez utiliser une instruction UPDATE pour définir la valeur d'une nouvelle colonne sur "False" lorsqu'elle est NULL.

    Pour en savoir plus et obtenir des exemples de code, consultez la section Utiliser le LMD partitionné.

    Vous pouvez utiliser des écritures par lot pour un grand nombre d'opérations d'écriture sans opérations de lecture qui ne nécessitent pas de transactions atomiques. Pour en savoir plus, consultez Modifier des données à l'aide d'écritures par lot.

Que sont les mutations ?

Une mutation représente une séquence d'opérations d'insertion, de mise à jour et de suppression que Spanner applique de manière atomique à différentes lignes et tables d'une base de données. Vous pouvez inclure des opérations qui s'appliquent à différentes lignes ou à différentes tables d'une mutation. Après avoir défini une ou plusieurs mutations contenant une ou plusieurs écritures, vous devez appliquer la mutation pour valider les écritures. Chaque modification est appliquée dans l'ordre dans lequel elles ont été ajoutées à la mutation.

Pour en savoir plus et obtenir des exemples de code, consultez la section Insérer, mettre à jour et supprimer des données à l'aide de mutations.

Comparaison des fonctionnalités entre LMD et mutations

Le tableau suivant récapitule la prise en charge des opérations et des fonctionnalités courantes de la base de données par le LMD et les mutations.

Opérations LMD Mutations
Insérer des données Compatible Compatible
Supprimer des données Compatible Compatible
Mettre à jour des données Compatible Compatible
Insérer ou ignorer des données Compatible Non compatible
Lecture de vos écritures (RYW) Compatible Non compatible
Insérer ou mettre à jour des données (upsert) Compatible Compatible
Syntaxe SQL Compatible Non compatible
Vérification des contraintes Après chaque instruction Au moment du commit
Application de la limite de mutations (index compris) Par instruction (réinitialisation après l'exécution) Par commit (cumulatif)

Le LMD et les mutations diffèrent dans leur compatibilité avec les fonctionnalités suivantes :

  • Lecture de vos écritures : lecture des résultats non validés dans une transaction active. Les modifications que vous apportez à l'aide d'instructions LMD sont visibles par les instructions suivantes dans la même transaction. Cette méthode est différente des mutations, avec lesquelles les modifications ne sont visibles dans les opérations de lecture (y-compris les lectures effectuées dans la même transaction) que lors du commit de la transaction. En effet, les mutations d'une transaction sont mises en mémoire tampon côté client (localement) et envoyées au serveur dans le cadre de l'opération de commit. Par conséquent, les mutations de la requête de commit ne sont pas visibles par les instructions SQL ou LMD de la même transaction.

  • Vérification des contraintes : Spanner vérifie les contraintes après chaque instruction LMD. Cette méthode diffère de l'utilisation de mutations, où Spanner met en mémoire tampon les mutations dans le client jusqu'au commit et vérifie les contraintes au moment du commit. L'évaluation des contraintes après chaque instruction LMD permet à Spanner de garantir que les données renvoyées par une requête ultérieure dans la même transaction sont cohérentes avec le schéma.

  • Application de la limite de mutations : pour le LMD, la limite de 80 000 mutations (index compris) est appliquée par instruction et se réinitialise après l'exécution de l'instruction. Cela permet à une seule transaction d'exécuter plusieurs instructions LMD qui dépassent collectivement 80 000 mutations, à condition qu'aucune instruction ne dépasse la limite. Pour l'API Mutation, qui ne peut être utilisée que dans le cadre de l'opération de commit, la limite de 80 000 mutations (y compris les index) est cumulative pour toutes les mutations du commit. Les deux méthodes sont soumises à la limite de taille de transaction de 100 Mio.

  • Syntaxe SQL : le LMD offre un moyen conventionnel de manipuler les données. Vous pouvez réutiliser les compétences SQL pour modifier les données à l'aide de l'API LMD.

Bonne pratique - éviter de mélanger LMD et mutation dans la même transaction

Si une transaction contient à la fois des instructions LMD et des mutations dans la requête de commit, Spanner exécute les instructions LMD avant les mutations. Pour éviter de devoir prendre en compte l'ordre d'exécution dans le code de votre bibliothèque cliente, vous devez utiliser soit les instructions LMD, soit les mutations d'une même transaction, mais pas les deux.

L'exemple Java suivant illustre un comportement potentiellement surprenant. Le code insère deux lignes dans des Albums à l'aide de l'API Mutation. L'extrait appelle ensuite executeUpdate() pour mettre à jour les lignes nouvellement insérées et executeQuery() pour lire les albums mis à jour.

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;
              }
            });
}

En exécutant ce code, vous verriez 0 enregistrement mis à jour. Pourquoi ? Cela est dû aux modifications apportées à l'aide des Mutations, qui ne sont pas visibles pour les instructions suivantes jusqu'au commit de la transaction. Idéalement, nous aurions dû mettre en mémoire tampon les écritures seulement à la toute fin de la transaction.

Étape suivante