Comparación del DML y las mutaciones

El lenguaje de manipulación de datos (DML) y las mutaciones son dos API de Cloud Spanner que puedes usar para modificar datos. Cada uno ofrece funciones similares de manipulación de datos. En esta página, se comparan ambos enfoques.

¿Qué es el lenguaje de manipulación de datos (DML)?

El lenguaje de manipulación de datos (DML) en Cloud Spanner te permite manipular datos en las tablas de tu base de datos mediante declaraciones INSERT, UPDATE y DELETE. Puedes ejecutar declaraciones DML con las bibliotecas cliente, Cloud Console y gcloud Spanner.

Cloud Spanner ofrece las siguientes dos implementaciones de ejecución de DML, cada una con diferentes propiedades.

  • DML estándar: Apto para cargas de trabajo estándar de procesamiento de transacciones en línea (OLTP).

    Para obtener más información, incluidas las muestras de código, consulta Cómo usar DML

  • DML particionado: Se diseñó para actualizaciones y eliminaciones masivas, como se muestra en los siguientes ejemplos.

    • Recolección de elementos no usados y limpieza periódicos. Por ejemplo, la eliminación de filas antiguas o la configuración de columnas como NULL.

    • El restablecimiento de columnas nuevas con valores predeterminados. Un ejemplo es usar una declaración UPDATE para establecer un nuevo valor de columna en False, donde actualmente es NULL.

    Para obtener más información, incluidas las muestras de código, consulta Usa DML particionado.

¿Qué son las mutaciones?

Una mutación representa una secuencia de inserciones, actualizaciones y eliminaciones que Cloud Spanner aplica de manera atómica a diferentes filas y tablas en una base de datos. Puedes incluir operaciones que se apliquen a diferentes filas o diferentes tablas en una mutación. Después de definir una o más mutaciones que contienen una o más operaciones de escritura, debes aplicarlas a fin de confirmarlas. Cada cambio se aplica en el orden en que se agregaron a la mutación.

Para obtener más información, incluidas las muestras de código, consulta Inserta, actualiza y borra datos mediante mutaciones.

Comparación de atributos entre DML y mutaciones

En la siguiente tabla, se resume la compatibilidad con DML y mutaciones de funciones y operaciones de base de datos comunes.

Operaciones DML Mutaciones
Inserta datos Admitido Admitido
Borrar datos Admitido Admitido
Actualizar datos Admitido Admitido
Lee tus escrituras (RYW) Admitido No compatible
Upsert (insertar o actualizar) No compatible Admitido
Sintaxis de SQL Admitido No compatible
Comprobación de restricciones Después de cada enunciado En el momento de la confirmación

El uso de DML y de mutaciones se diferencian de las siguientes funciones.

  • Semántica Lee tus escrituras: La lectura de tus escrituras se refiere a la lectura de resultados no confirmados dentro de una transacción activa. Los cambios que realices con las declaraciones DML podrán verse en las declaraciones posteriores de la misma transacción. Esto es diferente del uso de mutaciones, en el que los cambios no son visibles en ninguna lectura (incluidas las lecturas realizadas en la misma transacción) hasta que se confirma la transacción. Esto se debe a que las mutaciones de una transacción se almacenan en el búfer del cliente (de forma local) y se envían al servidor como parte de la operación de confirmación. Como resultado, las mutaciones de la solicitud de confirmación no son visibles para las instrucciones de SQL o DML dentro de la misma transacción.

  • Upsert: DML no admite una actualización nativa, una operación que inserta filas en una tabla de base de datos si aún no existen, o las actualiza si lo hacen. Sin embargo, hay una operación insert_or_update en el mundo de mutaciones. Las aplicaciones que usan DML pueden resolver esta limitación mediante la lectura de la fila primero y, luego, con la declaración DML adecuada.

  • Comprobación de restricciones: Cloud Spanner verifica las restricciones después de cada declaración DML. Esto es diferente del uso de mutaciones, en el que Cloud Spanner almacena las mutaciones en el cliente hasta la confirmación y verifica las restricciones en el momento de la confirmación. La evaluación de las restricciones después de cada declaración DML permite que Cloud Spanner garantice que los datos que muestra una consulta posterior en la misma transacción muestren datos coherentes con el esquema.

  • Sintaxis de SQL: DML proporciona una forma convencional de manipular datos. Puedes volver a usar las habilidades de SQL para alterar los datos mediante la API de DML.

Práctica recomendada: Evita mezclar DML y mutaciones en la misma transacción

Si una transacción contiene mutaciones y declaraciones DML en la solicitud de confirmación, Cloud Spanner ejecuta las declaraciones DML antes de las mutaciones. Para evitar tener que dar cuenta del orden de ejecución en el código de tu biblioteca cliente, debes usar las declaraciones DML o las mutaciones en una sola transacción, pero no en ambas.

En el siguiente ejemplo de Java, se ilustra un comportamiento potencialmente inesperado. El código inserta dos filas en los álbumes mediante la API de mutación. El fragmento realiza una llamada a executeUpdate() a fin de actualizar las filas insertadas recientemente y llama a executeQuery() para leer los álbumes actualizados.

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

Si ejecutaras este código, verás 0 registros actualizados. ¿Por qué? Esto sucede porque los cambios que realizamos con mutaciones no son visibles para las declaraciones posteriores hasta que se confirma la transacción. Lo ideal sería tener escrituras almacenadas en búfer solo al final de la transacción.

Próximos pasos