Comparer le LMD et les mutations

Le langage de manipulation de données (LMD) et les mutations sont deux API de Spanner qui vous permettent de 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 des données dans 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 console Google 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 nulle.

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

    Vous pouvez utiliser les é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 la section Modifier des données à l'aide d'écritures par lot.

Que sont les mutations ?

Une mutation représente une séquence d'insertions, de mises à jour et de suppressions 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 (Insérer ou mettre à jour des données) Compatible Compatible
Syntaxe SQL Compatible Non compatible
Vérification des contraintes Après chaque instruction Au moment du commit

La compatibilité du LMD et des mutations diffère pour les fonctionnalités suivantes:

  • Lire vos écritures: lire les 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. En conséquence, les mutations dans la requête de commit ne sont pas visibles pour les instructions SQL ou LMD dans la même transaction.

  • Vérification des contraintes: Spanner vérifie les contraintes après chaque instruction LMD. Cette méthode est différente des mutations, pour lesquelles Spanner met les mutations en mémoire tampon 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 renvoient des données cohérentes avec le schéma.

  • Syntaxe SQL: le LMD constitue une méthode conventionnelle pour 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