El lenguaje de manipulación de datos particionado (DML particionado) está diseñado para los siguientes tipos de actualizaciones y eliminaciones masivas:
- Recolección de elementos no utilizados 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 el uso de una declaración
UPDATEpara configurar el valor de una columna nueva comoFalsesi, en el momento, se encuentra comoNULL.
El DML particionado no es adecuado para el procesamiento de transacciones a pequeña escala. Si deseas ejecutar una declaración en algunas filas, usa DML transaccionales con claves principales identificables. Para obtener más información, consulta la sección sobre cómo usar DML.
Si necesitas confirmar una gran cantidad de escrituras ciegas, pero no requieres una transacción atómica, puedes modificar tus tablas de Spanner de forma masiva con la escritura por lotes. Para obtener más información, consulta Cómo modificar datos con escrituras por lotes.
Puedes obtener estadísticas sobre las consultas DML particionadas activas y su progreso en las tablas de estadísticas de tu base de datos de Spanner. Para obtener más información, consulta Estadísticas de DML particionadas activas.
DML y DML particionado
Spanner admite dos modos de ejecución para las declaraciones DML:
DML, que es adecuado para el procesamiento de transacciones. Para obtener más información, consulta la sección sobre cómo usar DML .
DML particionado, que permite operaciones a gran escala en toda la base de datos con un impacto mínimo en el procesamiento simultáneo de transacciones, ya que particiona el espacio clave y ejecuta la declaración en particiones en distintas transacciones de menor alcance. Para obtener más información, consulta la sección sobre cómo usar DML particionado.
En la siguiente tabla, se destacan algunas de las diferencias entre los dos modos de ejecución.
| DML | DML particionado |
|---|---|
Es posible que se bloqueen las filas que no coinciden con la cláusula WHERE. |
Solo se bloquean las filas que coinciden con la cláusula WHERE. |
| Se aplican los límites de tamaño de transacciones. | Spanner controla los límites de transacciones y los límites de simultaneidad por transacción. |
| No es necesario que las declaraciones sean idempotentes. | Una declaración DML debe ser idempotente para garantizar resultados coherentes. |
| Una transacción puede incluir varias instrucciones de SQL y declaraciones DML. | Una transacción particionada puede incluir solo una declaración DML. |
| No hay restricciones para la complejidad de las declaraciones. | Las declaraciones deben poder particionarse por completo. |
| Las transacciones de lectura y escritura se crean en el código del cliente. | Spanner crea las transacciones. |
Particionable e idempotente
Cuando se ejecuta una declaración DML particionada, las filas de una partición no tienen acceso a las filas de otras particiones, y no puedes elegir cómo Spanner crea las particiones. La partición garantiza la escalabilidad, pero también implica que las declaraciones DML particionadas deben poder particionarse por completo. Es decir, la declaración DML particionada debe poder expresarse como la unión de un conjunto de sentencias, en la que cada sentencia accede a una sola fila de la tabla y no tiene acceso a ninguna otra tabla. Por ejemplo, una declaración DML que accede a varias tablas o realiza una unión de tabla con sí misma no es particionable. Si la declaración DML no es particionable, Spanner muestra el error BadUsage.
Estas declaraciones DML se pueden particionar por completo, ya que cada una se puede aplicar a una sola fila de la tabla:
UPDATE Singers SET LastName = NULL WHERE LastName = '';
DELETE FROM Albums WHERE MarketingBudget > 10000;
Esta declaración DML no se puede particionar por completo, ya que accede a varias tablas:
# Not fully partitionable
DELETE FROM Singers WHERE
SingerId NOT IN (SELECT SingerId FROM Concerts);
Spanner puede ejecutar una declaración DML particionada varias veces en algunas particiones debido a reintentos a nivel de la red. Como resultado, una declaración se puede ejecutar más de una vez en una fila. Por lo tanto, la declaración debe ser idempotente para obtener resultados coherentes. Una declaración es idempotente si, cuando se ejecuta varias veces en una sola fila, genera el mismo resultado.
Esta declaración DML es idempotente:
UPDATE Singers SET MarketingBudget = 1000 WHERE true;
Esta declaración DML no es idempotente:
UPDATE Singers SET MarketingBudget = 1.5 * MarketingBudget WHERE true;
Borra filas de tablas superiores con tablas secundarias indexadas
Cuando usas una declaración DML particionada para borrar filas en una tabla superior, la
operación podría fallar con el error: The transaction contains too many
mutations. Esto ocurre si la tabla superior tiene tablas secundarias intercaladas que contienen un índice global. Las mutaciones en las filas de la tabla secundaria no se
cuentan en el límite de mutación de la transacción.
Sin embargo, se cuentan las mutaciones correspondientes en las entradas de índice. Si se ve afectada una gran cantidad de entradas de índice de la tabla secundaria, es posible que la transacción supere el límite de mutación.
Para evitar este error, borra las filas en dos declaraciones DML particionadas separadas:
- Ejecuta una eliminación particionada en las tablas secundarias.
- Ejecuta una eliminación particionada en la tabla superior.
Este proceso de dos pasos ayuda a mantener el recuento de mutaciones dentro de los límites permitidos para cada transacción. De lo contrario, puedes quitar el índice global de la tabla secundaria antes de borrar las filas superiores.
Bloqueo de filas
Spanner adquiere un bloqueo solo si una fila es candidata para una actualización o eliminación. Este comportamiento es diferente de
la ejecución de DML, que podría bloquear como solo lectura
las filas que no coinciden con la cláusula WHERE.
Ejecución y transacciones
En función del método de la biblioteca cliente que elijas para la ejecución, una declaración DML estará particionada o no. Cada biblioteca cliente proporciona distintos métodos para la ejecución de DML y la ejecución de DML particionado.
Solo puedes ejecutar una declaración DML particionada en una llamada al método de la biblioteca cliente.
Spanner no aplica las declaraciones DML particionadas de forma atómica en toda la tabla. Sin embargo, aplica las declaraciones DML particionadas de forma atómica en cada partición.
El DML particionado no admite la confirmación ni la reversión. Spanner ejecuta y aplica la declaración DML de inmediato.
- Si cancelas la operación, Spanner cancela las particiones en ejecución y no inicia las restantes. Spanner no revierte ninguna partición que ya se haya ejecutado.
- Si la ejecución de la declaración causa un error, la ejecución se detiene en todas las particiones y Spanner muestra ese error para toda la operación. Algunos ejemplos de errores son los incumplimientos de las restricciones de tipo de datos
, de
UNIQUE INDEXy deON DELETE NO ACTION. Según el momento en que falló la ejecución, es posible que la declaración se haya ejecutado correctamente en algunas particiones y que nunca se haya ejecutado en otras.
Si la declaración DML particionada se realizó con éxito, Spanner ejecutó la declaración al menos una vez en cada partición del rango clave.
Recuento de filas modificadas
Una declaración DML particionada muestra un límite inferior en la cantidad de filas modificadas. Es posible que no sea un recuento exacto de la cantidad de filas modificadas, ya que no hay garantía de que Spanner cuente todas las filas modificadas.
Límites de transacciones
Spanner crea las particiones y las transacciones que necesita para ejecutar una declaración DML particionada. Se aplican los límites de transacciones o los límites de simultaneidad por transacción, pero Spanner intenta mantener las transacciones dentro de los límites.
Spanner permite un máximo de 20,000 declaraciones DML particionadas en simultáneo por base de datos.
Características no compatibles
Spanner no admite algunas funciones para el DML particionado:
INSERTno es compatible.- Google Cloud Consola: No puedes ejecutar declaraciones DML particionadas en la Google Cloud consola.
- Creación de perfiles y planes de consulta: La CLI de Google Cloud y las bibliotecas cliente no son compatibles con la creación de perfiles y los planes de consulta.
- Subconsultas que leen desde otra tabla o una fila diferente de la misma tabla.
Para situaciones complejas, como mover una tabla o transformaciones que requieren uniones entre tablas, considera usar el conector de Dataflow.
Prácticas recomendadas
Aplica las siguientes prácticas recomendadas para mejorar el rendimiento de tus declaraciones DML particionadas:
- Evita la alta simultaneidad: Ejecutar una gran cantidad de declaraciones DML particionadas en simultáneo (por ejemplo, más de 100) puede generar contención de bloqueo en las tablas internas del sistema, lo que degrada el rendimiento. En lugar de ejecutar una gran cantidad de declaraciones simultáneas, usa una sola declaración DML particionada.
- Utiliza
PDML_MAX_PARALLELISM: Para aumentar la capacidad de procesamiento de una sola declaración DML particionada, en especial en tablas con muchas divisiones, establece un valor más alto para laPDML_MAX_PARALLELISMsugerencia de sentencia. Esto permite que la declaración única use más paralelismo de forma interna. Si estableces un valor más alto paraPDML_MAX_PARALLELISM, se generará un mayor uso de procesamiento, por lo que debes intentar equilibrar el uso de procesamiento y el aumento de la velocidad de procesamiento. - Permite que Spanner controle la partición: Evita fragmentar tus datos de forma manual (por ejemplo, con rangos de clave primaria) y ejecutar declaraciones DML particionadas separadas en cada fragmento. El DML particionado está diseñado para particionar de manera eficiente el trabajo en toda la tabla. La fragmentación personalizada suele aumentar la sobrecarga y puede empeorar la contención.
- Comprende el alcance de la partición: Las operaciones DML particionadas se paralelizan en todas las divisiones de toda la base de datos, no solo en las divisiones que contienen datos para la tabla que se modifica. Esto significa que, para las bases de datos con una gran cantidad de divisiones, puede haber una sobrecarga incluso si la tabla de destino es pequeña o si los datos modificados están localizados. Es posible que el DML particionado no sea la opción más eficiente para modificar una porción muy pequeña de una base de datos grande.
- Considera alternativas para eliminaciones pequeñas y frecuentes: Para los casos de uso que implican eliminaciones frecuentes de una pequeña cantidad de filas conocidas, el uso de declaraciones DML dentro de las transacciones o la API de BatchWrite puede ofrecer un mejor rendimiento y una menor sobrecarga que el uso de DML particionado.
Ejemplos
En el siguiente ejemplo de código, se actualiza la columna MarketingBudget de la tabla Albums.
C++
Usa la función ExecutePartitionedDml() para ejecutar una declaración DML particionada.
C#
Usa el método ExecutePartitionedUpdateAsync() para ejecutar una declaración DML particionada.
Go
Usa el método PartitionedUpdate() para ejecutar una declaración DML particionada.
Java
Usa el método executePartitionedUpdate() para ejecutar una declaración DML particionada.
Node.js
Usa el método runPartitionedUpdate() para ejecutar una declaración DML particionada.
PHP
Usa el método executePartitionedUpdate() para ejecutar una declaración DML particionada.
Python
Usa el método execute_partitioned_dml() para ejecutar una declaración DML particionada.
Ruby
Usa el método execute_partitioned_update() para ejecutar una declaración DML particionada.
En el siguiente ejemplo de código, se borran las filas de la tabla Singers según la columna SingerId.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Próximos pasos
Obtén información para modificar datos con DML.
Obtén información sobre las prácticas recomendadas para el lenguaje de manipulación de datos (DML).
Para obtener información sobre las diferencias entre DML y las mutaciones, consulta Compara DML y mutaciones
Considera usar el conector de Dataflow para otras situaciones de transformación de datos