En esta página se describen las transacciones de Spanner y se presentan las interfaces de transacciones de lectura y escritura, de solo lectura y de DML con particiones de Spanner.
Una transacción en Spanner es un conjunto de lecturas y escrituras que se ejecutan de forma atómica en un único punto lógico en el tiempo en columnas, filas y tablas de una base de datos.
Una sesión se usa para realizar transacciones en una base de datos de Spanner. Una sesión representa un canal de comunicación lógico con el servicio de base de datos de Spanner. Las sesiones pueden ejecutar una o varias transacciones a la vez. Para obtener más información, consulta Sesiones.
Tipos de transacciones
Spanner admite los siguientes tipos de transacciones, cada uno diseñado para patrones de interacción de datos específicos:
Lectura y escritura: estas transacciones usan el bloqueo pesimista y, si es necesario, una confirmación en dos fases. Puede que fallen y requieran reintentos. Aunque están limitadas a una sola base de datos, pueden modificar datos en varias tablas de esa base de datos.
Solo lectura: estas transacciones garantizan la coherencia de los datos en varias operaciones de lectura, pero no permiten modificar los datos. Se ejecutan en una marca de tiempo determinada por el sistema para mantener la coherencia o en una marca de tiempo anterior configurada por el usuario. A diferencia de las transacciones de lectura y escritura, no requieren una operación de confirmación ni bloqueos, aunque pueden pausarse para esperar a que finalicen las operaciones de escritura en curso.
DML particionado: este tipo de transacción ejecuta instrucciones de DML como operaciones de DML particionado. Está optimizada para actualizaciones y eliminaciones de datos a gran escala, como la limpieza de datos o la inserción de datos en bloque. Si tienes que hacer muchas escrituras que no necesitan una transacción atómica, te recomendamos que uses escrituras por lotes. Para obtener más información, consulta Modificar datos mediante escrituras por lotes.
Transacciones de lectura y escritura
Usa transacciones de lectura y escritura con bloqueo para leer, modificar y escribir datos de forma atómica en cualquier parte de una base de datos. Este tipo de transacción es coherente externamente.
Minimiza el tiempo que una transacción está activa. Las transacciones de menor duración aumentan la probabilidad de que se completen correctamente y reducen la contención.
Spanner intenta mantener activas las exclusivas de lectura mientras la transacción siga realizando lecturas y no haya finalizado mediante las operaciones sessions.commit
u sessions.rollback
.
Si el cliente permanece inactivo durante largos periodos, Spanner podría liberar los bloqueos de la transacción y abortarla.
Conceptualmente, una transacción de lectura y escritura consta de cero o más lecturas o instrucciones SQL seguidas de sessions.commit
. En cualquier momento antes del sessions.commit
,
el cliente puede enviar una solicitud sessions.rollback
para cancelar la transacción.
Para realizar una operación de escritura que dependa de una o varias operaciones de lectura, usa una transacción de lectura y escritura con bloqueo:
- Si debes confirmar una o varias operaciones de escritura de forma atómica, realiza esas escrituras en la misma transacción de lectura y escritura. Por ejemplo, si transfiere 200 $ de la cuenta A a la cuenta B, realice las dos operaciones de escritura (disminuir 200 $en la cuenta A y aumentar 200 $en la cuenta B) y las lecturas de los saldos iniciales de las cuentas en la misma transacción.
- Si quieres duplicar el saldo de la cuenta A, realiza las operaciones de lectura y escritura en la misma transacción. De esta forma, el sistema lee el saldo antes de duplicarlo y, a continuación, lo actualiza.
- Si vas a realizar una o varias operaciones de escritura que dependen de los resultados de una o varias operaciones de lectura, realiza esas escrituras y lecturas en la misma transacción de lectura y escritura, aunque las operaciones de escritura no se ejecuten. Por ejemplo, si quieres transferir 200 $de la cuenta A a la cuenta B solo si el saldo actual de A es superior a 500 $, incluye la lectura del saldo de A y las operaciones de escritura condicionales en la misma transacción, aunque no se produzca la transferencia.
Para realizar operaciones de lectura, usa un único método de lectura o una transacción de solo lectura:
- Si solo vas a realizar operaciones de lectura y puedes expresar la operación de lectura con un único método de lectura, usa ese método o una transacción de solo lectura. A diferencia de las transacciones de lectura y escritura, las lecturas únicas no adquieren bloqueos.
Interfaz
Las bibliotecas de cliente de Spanner proporcionan una interfaz para ejecutar un cuerpo de trabajo en una transacción de lectura y escritura, con reintentos para las anulaciones de transacciones. Una transacción de Spanner puede requerir varios reintentos antes de confirmarse.
Las transacciones se pueden anular por varios motivos. Por ejemplo, si dos transacciones intentan modificar datos simultáneamente, puede producirse un interbloqueo. En estos casos, Spanner aborta una transacción para que la otra pueda continuar. Con menos frecuencia, los eventos transitorios de Spanner también pueden provocar la cancelación de transacciones.
Como las transacciones son atómicas, una transacción anulada no afecta a la base de datos. Vuelve a intentar la transacción en la misma sesión para aumentar las tasas de éxito. Cada reintento que da como resultado un error ABORTED
aumenta la prioridad de bloqueo de la transacción.
Cuando usas una transacción en una biblioteca de cliente de Spanner, defines el cuerpo de la transacción como un objeto de función. Esta función encapsula las lecturas y escrituras realizadas en una o varias tablas de la base de datos. La biblioteca de cliente de Spanner ejecuta esta función repetidamente hasta que la transacción se confirma correctamente o se produce un error que no se puede volver a intentar.
Ejemplo
Supongamos que tiene una columna MarketingBudget
en la tabla Albums
:
CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), MarketingBudget INT64 ) PRIMARY KEY (SingerId, AlbumId);
El departamento de marketing te pide que transfieras 200.000 € del presupuesto de Albums
(2, 2)
a Albums (1, 1)
, pero solo si hay dinero disponible en el presupuesto de ese álbum. Debes usar una transacción de lectura y escritura con bloqueo para esta operación, ya que la transacción puede realizar escrituras en función del resultado de una lectura.
A continuación, se muestra cómo ejecutar una transacción de lectura y escritura:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Semántica
En esta sección se describe la semántica de las transacciones de lectura y escritura en Spanner.
Propiedades
Una transacción de lectura y escritura en Spanner ejecuta un conjunto de lecturas y escrituras de forma atómica. La marca de tiempo en la que se ejecutan las transacciones de lectura y escritura coincide con el tiempo transcurrido. El orden de serialización coincide con el orden de esta marca de tiempo.
Las transacciones de lectura y escritura proporcionan las propiedades ACID de las bases de datos relacionales. Las transacciones de lectura y escritura de Spanner ofrecen propiedades más sólidas que las transacciones ACID típicas.
Gracias a estas propiedades, como desarrollador de aplicaciones, puedes centrarte en la corrección de cada transacción por separado, sin preocuparte por cómo proteger su ejecución de otras transacciones que puedan ejecutarse al mismo tiempo.
Aislamiento de las transacciones de lectura y escritura
Después de confirmar correctamente una transacción que contiene una serie de lecturas y escrituras, verás lo siguiente:
- La transacción devuelve valores que reflejan una instantánea coherente en la marca de tiempo de confirmación de la transacción.
- Las filas o los intervalos vacíos permanecen vacíos en el momento de la confirmación.
- La transacción confirma todas las escrituras en la marca de tiempo de confirmación de la transacción.
- Ninguna transacción puede ver las escrituras hasta que se confirme la transacción.
Los controladores de cliente de Spanner incluyen una lógica de reintento de transacciones que oculta los errores transitorios volviendo a ejecutar la transacción y validando los datos que observa el cliente.
El efecto es que todas las lecturas y escrituras parecen haber ocurrido en un único momento, tanto desde la perspectiva de la transacción en sí como desde la perspectiva de otros lectores y escritores de la base de datos de Spanner. Esto significa que las lecturas y las escrituras se producen en la misma marca de tiempo. Para ver un ejemplo, consulta Serialización y coherencia externa.
Aislamiento de las transacciones de lectura
Cuando una transacción de lectura y escritura solo realiza operaciones de lectura, ofrece garantías de coherencia similares a las de una transacción de solo lectura. Todas las lecturas de la transacción devuelven datos de una marca de tiempo coherente, incluida la confirmación de filas no existentes.
Una de las diferencias es que una transacción de lectura y escritura se confirma sin ejecutar una operación de escritura. En este caso, no se garantiza que los datos leídos en la transacción no hayan cambiado en la base de datos entre la operación de lectura y la confirmación de la transacción.
Para asegurarse de que los datos estén actualizados y validar que no se han modificado desde la última vez que se obtuvieron, es necesario realizar una lectura posterior. Esta lectura se puede realizar en otra transacción de lectura y escritura o con una lectura fuerte.
Para obtener una eficiencia óptima, si una transacción solo realiza lecturas, usa una transacción de solo lectura en lugar de una transacción de lectura y escritura.
Atomicidad, coherencia y durabilidad
Además del aislamiento, Spanner ofrece las demás garantías de las propiedades ACID:
- Atomicidad. Una transacción se considera atómica si todas sus operaciones se completan correctamente o si no se completa ninguna. Si falla alguna operación de una transacción, se revierte toda la transacción a su estado original, lo que garantiza la integridad de los datos.
- Coherencia. Una transacción debe mantener la integridad de las reglas y las restricciones de la base de datos. Una vez completada una transacción, la base de datos debe estar en un estado válido y cumplir las reglas predefinidas.
- Durabilidad. Una vez que se confirma una transacción, sus cambios se almacenan de forma permanente en la base de datos y se conservan en caso de que se produzcan fallos en el sistema, cortes de suministro eléctrico u otras interrupciones.
Serialización y coherencia externa
Spanner ofrece sólidas garantías transaccionales, como la serialización y la coherencia externa. Estas propiedades aseguran que los datos sigan siendo coherentes y que las operaciones se realicen en un orden predecible, incluso en un entorno distribuido.
La serializabilidad asegura que todas las transacciones se ejecuten una tras otra en un orden único y secuencial, aunque se procesen simultáneamente. Spanner lo consigue asignando marcas de tiempo de confirmación a las transacciones, lo que refleja el orden en el que se han confirmado.
Spanner ofrece una garantía aún mayor, conocida como coherencia externa. Esto significa que las transacciones no solo se completan en un orden reflejado por sus marcas de tiempo de confirmación, sino que estas marcas de tiempo también se ajustan a la hora real. De esta forma, puedes comparar las marcas de tiempo de las confirmaciones con la hora real, lo que te proporciona una vista coherente y ordenada a nivel mundial de tus datos.
En esencia, si una transacción Txn1
se confirma antes que otra transacción Txn2
en tiempo real, la marca de tiempo de confirmación de Txn1
es anterior a la de Txn2
.
Veamos un ejemplo:
En este caso, durante la cronología t
:
- La transacción
Txn1
lee los datosA
, prepara una escritura enA
y, a continuación, se confirma correctamente. - La transacción
Txn2
comienza después de que se inicieTxn1
. Lee los datosB
y, a continuación, los datosA
.
Aunque Txn2
haya empezado antes de que se completara Txn1, Txn2
observa los cambios que Txn1
ha hecho en A
. Esto se debe a que Txn2
lee A
después de que Txn1
haya confirmado
su escritura en A
.
Aunque Txn1
y Txn2
pueden superponerse en su tiempo de ejecución, sus marcas de tiempo de confirmación, c1
y c2
respectivamente, imponen un orden de transacción lineal. Esto significa lo siguiente:
- Todas las lecturas y escrituras de
Txn1
parecen haber ocurrido en un solo momento,c1
. - Todas las lecturas y escrituras de
Txn2
parecen haber ocurrido en un solo momento,c2
. - Es fundamental que
c1
sea anterior ac2
en las escrituras confirmadas, aunque las escrituras se hayan producido en máquinas diferentes. SiTxn2
solo realiza lecturas,c1
es anterior o se produce al mismo tiempo quec2
.
Este orden estricto significa que, si una operación de lectura posterior observa los efectos de Txn2
, también observa los efectos de Txn1
. Esta propiedad tiene el valor true en todas las transacciones confirmadas correctamente.
Garantías de lectura y escritura en caso de fallo de la transacción
Si falla una llamada para ejecutar una transacción, las garantías de lectura y escritura que tengas dependerán del error con el que haya fallado la llamada de confirmación subyacente.
Por ejemplo, un error como "Row Not Found" o "Row Already Exists" significa que se ha producido un error al escribir las mutaciones almacenadas en el búfer. Por ejemplo, una fila que el cliente está intentando actualizar no existe. En ese caso, las lecturas son coherentes, las escrituras no se aplican y la inexistencia de la fila también es coherente con las lecturas.
Garantías de lectura y escritura en caso de fallo de la transacción
Cuando falla una transacción de Spanner, las garantías que recibes para las lecturas y escrituras dependen del error específico que se haya producido durante la operación commit
.
Por ejemplo, un mensaje de error como "Row Not Found" (No se ha encontrado la fila) o "Row Already Exists" (La fila ya existe) indica que hay un problema al escribir mutaciones almacenadas en búfer. Esto puede ocurrir si, por ejemplo, no existe una fila que el cliente esté intentando actualizar. En estos casos:
- Las lecturas son coherentes: se garantiza que los datos leídos durante la transacción son coherentes hasta el momento en que se produce el error.
- No se aplican las escrituras: las mutaciones que ha intentado la transacción no se han confirmado en la base de datos.
- Coherencia de las filas: la inexistencia (o el estado) de la fila que ha activado el error es coherente con las lecturas realizadas en la transacción.
Puedes cancelar operaciones de lectura asíncronas en Spanner en cualquier momento sin que afecte a otras operaciones en curso de la misma transacción. Esta flexibilidad es útil si se cancela una operación de nivel superior o si decides abortar una lectura en función de los resultados iniciales.
Sin embargo, es importante tener en cuenta que solicitar la cancelación de una lectura no garantiza que se detenga inmediatamente. Después de una solicitud de cancelación, la operación de lectura puede seguir ocurriendo:
- Se completa correctamente: la lectura puede terminar de procesarse y devolver resultados antes de que se aplique la cancelación.
- Fallo por otro motivo: la lectura podría finalizar debido a otro error, como una cancelación.
- Devuelve resultados incompletos: la lectura puede devolver resultados parciales, que se validan como parte del proceso de confirmación de la transacción.
También es importante tener en cuenta la diferencia con las operaciones de commit
de transacción:
cancelar una commit
aborta toda la transacción, a menos que la transacción ya se haya
confirmado o haya fallado por otro motivo.
Rendimiento
En esta sección se describen los problemas que afectan al rendimiento de las transacciones de lectura y escritura.
Control de simultaneidad de bloqueo
Spanner permite que varios clientes interactúen con la misma base de datos simultáneamente. Para mantener la coherencia de los datos en estas transacciones simultáneas, Spanner tiene un mecanismo de bloqueo que usa bloqueos compartidos y exclusivos.
Cuando una transacción realiza una operación de lectura, Spanner adquiere bloqueos de lectura compartidos en los datos pertinentes. Estos bloqueos compartidos permiten que otras operaciones de lectura simultáneas accedan a los mismos datos. Esta simultaneidad se mantiene hasta que tu transacción se prepara para confirmar sus cambios.
Durante la fase de confirmación, a medida que se aplican las escrituras, la transacción intenta actualizar sus bloqueos a bloqueos exclusivos. Para ello, hace lo siguiente:
- Bloquea cualquier solicitud de bloqueo de lectura compartido nueva en los datos afectados.
- Espera a que se liberen todos los bloqueos de lectura compartidos de esos datos.
- Una vez que se han borrado todos los bloqueos de lectura compartidos, se coloca un bloqueo exclusivo, lo que le da acceso exclusivo a los datos durante la escritura.
Notas sobre los bloqueos:
- Granularidad: Spanner aplica bloqueos a nivel de fila y columna. Esto significa que, si la transacción
T1
tiene un bloqueo en la columnaA
de la filaalbumid
, la transacciónT2
puede seguir escribiendo simultáneamente en la columnaB
de la misma filaalbumid
sin que haya ningún conflicto. - Escrituras sin lecturas: para las escrituras sin lecturas, Spanner no requiere un bloqueo exclusivo. En su lugar, usa un bloqueo compartido de escritura. Esto se debe a que el orden de aplicación de las escrituras sin lecturas se determina por sus marcas de tiempo de confirmación, lo que permite que varios escritores operen en el mismo elemento simultáneamente sin conflictos. Un bloqueo exclusivo solo es necesario si tu transacción primero lee los datos que pretende escribir.
- Índices secundarios para búsquedas de filas: al realizar búsquedas de filas en una transacción de lectura y escritura, el uso de índices secundarios puede mejorar significativamente el rendimiento. Al usar índices secundarios para limitar las filas analizadas a un intervalo más pequeño, Spanner bloquea menos filas en la tabla, lo que permite una mayor modificación simultánea de las filas fuera de ese intervalo específico.
- Acceso exclusivo a recursos externos: los bloqueos internos de Spanner se han diseñado para mantener la coherencia de los datos en la propia base de datos de Spanner. No los utilice para garantizar el acceso exclusivo a recursos fuera de Spanner. Spanner puede anular transacciones por varios motivos, como optimizaciones internas del sistema, como el movimiento de datos entre recursos de computación. Si se vuelve a intentar una transacción (ya sea de forma explícita mediante el código de tu aplicación o de forma implícita mediante bibliotecas de cliente como el controlador JDBC de Spanner), se garantiza que los bloqueos se han mantenido solo durante el intento de confirmación correcto.
- Estadísticas de bloqueo: para diagnosticar e investigar conflictos de bloqueo en tu base de datos, puedes usar la herramienta de introspección Estadísticas de bloqueo.
Detección de interbloqueos
Spanner detecta cuándo se pueden producir interbloqueos en varias transacciones y fuerza la cancelación de todas las transacciones menos una. Imagina esta situación:
Txn1
tiene un bloqueo en el registro A
y está esperando un bloqueo en el registro B
, mientras que
Txn2
tiene un bloqueo en el registro B
y está esperando un bloqueo en el registro A
. Para resolver este problema, una de las transacciones debe abortar, liberando su bloqueo y permitiendo que la otra continúe.
Spanner usa el algoritmo estándar wound-wait para detectar interbloqueos. En segundo plano, Spanner monitoriza la antigüedad de cada transacción que solicita bloqueos en conflicto. Permite que las transacciones más antiguas aborten las más recientes. Una transacción más antigua es aquella cuya lectura, consulta o confirmación más antigua se produjo antes.
Al priorizar las transacciones más antiguas, Spanner se asegura de que todas las transacciones acaben adquiriendo bloqueos cuando tengan la antigüedad suficiente para tener una prioridad más alta. Por ejemplo, una transacción más antigua que necesite un bloqueo compartido de escritura puede anular una transacción más reciente que tenga un bloqueo compartido de lectura.
Ejecución distribuida
Spanner puede ejecutar transacciones en datos que abarcan varios servidores, aunque esta función conlleva un coste de rendimiento en comparación con las transacciones de un solo servidor.
¿Qué tipos de transacciones se pueden distribuir? Spanner puede distribuir la responsabilidad de las filas de la base de datos entre muchos servidores. Normalmente, el mismo servidor proporciona una fila y las filas de la tabla intercalada correspondientes, así como dos filas de la misma tabla con claves cercanas. Spanner puede realizar transacciones entre filas de diferentes servidores. Sin embargo, por lo general, las transacciones que afectan a muchas filas ubicadas en el mismo lugar son más rápidas y económicas que las que afectan a muchas filas dispersas por toda la base de datos o una tabla grande.
Las transacciones más eficientes de Spanner solo incluyen las lecturas y escrituras que se deben aplicar de forma atómica. Las transacciones son más rápidas cuando todas las lecturas y escrituras acceden a los datos en la misma parte del espacio de claves.
Transacciones de solo lectura
Además de bloquear las transacciones de lectura y escritura, Spanner ofrece transacciones de solo lectura.
Usa una transacción de solo lectura cuando necesites ejecutar más de una lectura en la misma marca de tiempo. Si puedes expresar tu lectura mediante uno de los métodos de lectura única de Spanner, debes usar ese método en su lugar. El rendimiento de usar una sola llamada de lectura de este tipo debería ser comparable al de una sola lectura realizada en una transacción de solo lectura.
Si vas a leer una gran cantidad de datos, te recomendamos que uses particiones para leer los datos en paralelo.
Como las transacciones de solo lectura no escriben, no mantienen bloqueos y no bloquean otras transacciones. Las transacciones de solo lectura observan un prefijo coherente del historial de confirmaciones de transacciones, por lo que tu aplicación siempre obtiene datos coherentes.
Interfaz
Spanner proporciona una interfaz para ejecutar un conjunto de tareas en el contexto de una transacción de solo lectura, con reintentos para las transacciones anuladas.
Ejemplo
En el siguiente ejemplo se muestra cómo usar una transacción de solo lectura para obtener datos coherentes de dos lecturas con la misma marca de tiempo:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Semántica
En esta sección se describe la semántica de las transacciones de solo lectura.
Transacciones de solo lectura de la copia
Cuando se ejecuta una transacción de solo lectura en Spanner, realiza todas sus lecturas en un único punto lógico en el tiempo. Esto significa que tanto la transacción de solo lectura como cualquier otro lector y escritor simultáneo ven una instantánea coherente de la base de datos en ese momento concreto.
Estas transacciones de solo lectura de la instantánea ofrecen un enfoque más sencillo para las lecturas coherentes en comparación con las transacciones de lectura y escritura con bloqueo. Estos son los motivos:
- Sin bloqueos: las transacciones de solo lectura no adquieren bloqueos. En su lugar, funcionan seleccionando una marca de tiempo de Spanner y ejecutando todas las lecturas en esa versión histórica de los datos. Como no usan bloqueos, no bloquearán las transacciones de lectura y escritura simultáneas.
- Sin cancelaciones: estas transacciones nunca se cancelan. Aunque pueden fallar si la marca de tiempo de lectura elegida se recoge como elemento no utilizado, la política de recogida de elementos no utilizados predeterminada de Spanner suele ser lo suficientemente generosa como para que la mayoría de las aplicaciones no tengan este problema.
- Sin confirmaciones ni reversiones: las transacciones de solo lectura no requieren llamadas a
sessions.commit
ni asessions.rollback
y, de hecho, no pueden hacerlo.
Para ejecutar una transacción de instantánea, el cliente define un límite de marca de tiempo, que indica a Spanner cómo seleccionar una marca de tiempo de lectura. Entre los tipos de límites de marca de tiempo se incluyen los siguientes:
- Lecturas sólidas: estas lecturas garantizan que verás los efectos de todas las transacciones confirmadas antes de que empezara la lectura. Todas las filas de una misma lectura son coherentes. Sin embargo, las lecturas sólidas no se pueden repetir, aunque sí devuelven una marca de tiempo, y la lectura de nuevo en esa misma marca de tiempo se puede repetir. Dos transacciones de solo lectura consecutivas pueden producir resultados diferentes debido a escrituras simultáneas. Las consultas en flujos de cambios deben usar este límite. Para obtener más información, consulta TransactionOptions.ReadOnly.strong.
- Obsoleto exacto: esta opción ejecuta lecturas en una marca de tiempo que especifiques, ya sea como una marca de tiempo absoluta o como una duración de obsolescencia relativa a la hora actual. De esta forma, se asegura de que se observe un prefijo coherente del historial de transacciones globales hasta esa marca de tiempo y se bloquean las transacciones conflictivas que puedan confirmarse con una marca de tiempo inferior o igual a la marca de tiempo de lectura. Aunque es ligeramente más rápido que los modos de obsolescencia limitada, puede devolver datos antiguos. Para obtener más información, consulta TransactionOptions.ReadOnly.read_timestamp y TransactionOptions.ReadOnly.exact_staleness.
- Obsolecencia limitada: Spanner selecciona la marca de tiempo más reciente dentro de un límite de obsolescencia definido por el usuario, lo que permite la ejecución en la réplica disponible más cercana sin bloquearse. Todas las filas devueltas son coherentes. Al igual que las lecturas sólidas, la obsolescencia limitada no se puede repetir, ya que las diferentes lecturas pueden ejecutarse en marcas de tiempo diferentes, incluso con el mismo límite. Estas lecturas se realizan en dos fases (negociación de la marca de tiempo y, a continuación, lectura) y suelen ser ligeramente más lentas que la obsolescencia exacta, pero a menudo devuelven resultados más recientes y es más probable que se ejecuten en una réplica local. Este modo solo está disponible para transacciones de solo lectura de un solo uso, ya que la negociación de la marca de tiempo requiere saber qué filas se leerán de antemano. Para obtener más información, consulta TransactionOptions.ReadOnly.max_staleness y TransactionOptions.ReadOnly.min_read_timestamp.
Transacciones de DML particionado
Puedes usar DML con particiones para ejecutar instrucciones UPDATE
y DELETE
a gran escala sin superar los límites de las transacciones ni bloquear una tabla completa. Spanner lo consigue particionando el espacio de claves y ejecutando las instrucciones DML en cada partición dentro de una transacción de lectura y escritura independiente.
Para usar DML no particionado, debes ejecutar instrucciones en transacciones de lectura y escritura que crees explícitamente en tu código. Para obtener más información, consulta el artículo sobre cómo usar DML.
Interfaz
Spanner proporciona la interfaz TransactionOptions.partitionedDml para ejecutar una única instrucción 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 instrucción DML con particiones.
C#
Usa el método ExecutePartitionedUpdateAsync()
para ejecutar una instrucción DML particionada.
Go
Usa el método PartitionedUpdate()
para ejecutar una instrucción DML particionada.
Java
Usa el método executePartitionedUpdate()
para ejecutar una instrucción DML particionada.
Node.js
Usa el método runPartitionedUpdate()
para ejecutar una instrucción DML particionada.
PHP
Usa el método executePartitionedUpdate()
para ejecutar una instrucción DML particionada.
Python
Usa el método execute_partitioned_dml()
para ejecutar una instrucción DML particionada.
Ruby
Usa el método execute_partitioned_update()
para ejecutar una instrucción DML particionada.
En el siguiente ejemplo de código se eliminan filas de la tabla Singers
en función de la columna SingerId
.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Semántica
En esta sección se describe la semántica de DML particionado.
Información sobre la ejecución de DML particionado
Solo puedes ejecutar una instrucción de DML particionado a la vez, ya sea mediante un método de biblioteca de cliente o la CLI de Google Cloud.
Las transacciones particionadas no admiten confirmaciones ni restauraciones. Spanner ejecuta y aplica la instrucción DML inmediatamente. Si cancelas la operación o esta falla, Spanner cancela todas las particiones en ejecución y no inicia ninguna de las restantes. Sin embargo, Spanner no revierte las particiones que ya se hayan ejecutado.
Estrategia de adquisición de bloqueos de DML particionado
Para reducir la contención de bloqueos, DML particionado adquiere bloqueos de lectura solo en las filas que coinciden con la cláusula WHERE
. Las transacciones independientes más pequeñas que se usan para cada partición también mantienen los bloqueos durante menos tiempo.
Límites de las transacciones de sesión
Cada sesión de Spanner puede tener una transacción activa a la vez. Esto incluye lecturas y consultas independientes, que internamente usan una transacción y se tienen en cuenta para este límite. Una vez completada una transacción, la sesión se puede volver a usar inmediatamente para la siguiente. No es necesario crear una sesión nueva para cada transacción.
Marcas de tiempo de lectura antiguas y recolección de elementos obsoletos de versiones
Spanner realiza la recogida de elementos obsoletos de versiones para recoger los datos eliminados o sobrescritos y recuperar el almacenamiento. De forma predeterminada, los datos de más de una hora se recuperan. Spanner no puede realizar lecturas en marcas de tiempo anteriores al VERSION_RETENTION_PERIOD
configurado, que tiene un valor predeterminado de una hora, pero se puede configurar hasta una semana. Si las lecturas son demasiado antiguas durante la ejecución, fallarán y devolverán el error FAILED_PRECONDITION
.
Consultas en flujos de cambios
Un flujo de cambios es un objeto de esquema que puedes configurar para monitorizar las modificaciones de datos en toda una base de datos, en tablas específicas o en un conjunto definido de columnas de una base de datos.
Cuando creas un flujo de cambios, Spanner define una función con valores de tabla (TVF) de SQL correspondiente. Puede usar esta TVF para consultar los registros de cambios de la secuencia de cambios asociada con el método sessions.executeStreamingSql
. El nombre de la función de valor de tabla se genera a partir del nombre del flujo de cambios y siempre empieza por READ_
.
Todas las consultas en las funciones de valor de tabla de flujo de cambios deben ejecutarse mediante la API sessions.executeStreamingSql
en una transacción de solo lectura de un solo uso con una timestamp_bound
de solo lectura sólida. La función de valor de tabla de flujo de cambios te permite especificar start_timestamp
y end_timestamp
para el intervalo de tiempo. Se puede acceder a todos los registros de cambios que se encuentren dentro del periodo de conservación mediante esta lectura de solo lectura segura
timestamp_bound
. Todos los demás
TransactionOptions
no son válidos para las consultas de flujo de cambios.
Además, si TransactionOptions.read_only.return_read_timestamp
se define como true
, el mensaje Transaction
que describe la transacción devuelve el valor especial 2^63 - 2
en lugar de una marca de tiempo de lectura válida. Debe descartar este valor especial y no usarlo en ninguna consulta posterior.
Para obtener más información, consulta el artículo Flujo de trabajo de consulta de secuencias de cambios.
Transacciones inactivas
Una transacción se considera inactiva si no tiene lecturas ni consultas de SQL pendientes y no ha iniciado ninguna en los últimos 10 segundos. Spanner puede anular las transacciones inactivas para evitar que mantengan bloqueos indefinidamente. Si se aborta una transacción inactiva, la confirmación falla y devuelve un error ABORTED
.
Ejecutar periódicamente una consulta pequeña, como SELECT 1
, dentro de la transacción
puede evitar que se quede inactiva.