Transacciones de varias declaraciones
BigQuery admite transacciones de varias declaraciones dentro de una sola consulta o en varias consultas cuando se usan sesiones. Una transacción con varias declaraciones te permite realizar operaciones de mutación, como insertar o borrar filas, en una o más tablas, y confirmar o revertir los cambios de forma atómica.
Los usos de las transacciones de varias declaraciones incluyen lo siguiente:
- Realizar mutaciones de DML en varias tablas como una sola transacción. Las tablas pueden abarcar varios conjuntos de datos o proyectos.
- Realizar mutaciones en una sola tabla en varias etapas, en función de cálculos intermedios.
Las transacciones garantizan las propiedades ACID y admiten el aislamiento de instantáneas. Durante una transacción, todas las lecturas muestran una instantánea coherente de las tablas a las que se hace referencia en la transacción. Si una declaración en una transacción modifica una tabla, los cambios son visibles para las declaraciones posteriores dentro de la misma transacción.
Alcance de la transacción
Una transacción debe incluirse en una sola consulta en SQL, excepto en
Session mode. Una consulta puede contener varias transacciones, pero no se pueden anidar. Puedes ejecutar transacciones de varias instrucciones en múltiples consultas en una sesión.
Para iniciar una transacción, usa el comando BEGIN TRANSACTION. La transacción finaliza cuando ocurre alguna de las siguientes situaciones:
- La consulta ejecuta una declaración
COMMIT TRANSACTION. Esta declaración confirma de forma atómica todos los cambios realizados dentro de la transacción. - La consulta ejecuta una declaración
ROLLBACK TRANSACTION. Con esta declaración, se descartan todos los cambios realizados dentro de la transacción. - La consulta termina antes de llegar a cualquiera de estas dos declaraciones. En ese caso, BigQuery revierte de forma automática la transacción.
Si se produce un error durante una transacción y la consulta tiene un controlador de excepciones, BigQuery transfiere el control al controlador de excepciones. Dentro del bloque de excepciones, puedes elegir si deseas confirmar o revertir la transacción.
Cuando el modo de sesión está inhabilitado, si se produce un error durante una transacción y no hay un controlador de excepciones, la consulta fallará y BigQuery revertirá automáticamente la transacción.
Cuando el modo de sesión está habilitado y no hay un controlador de excepciones, la transacción permanece activa hasta que se finaliza la sesión o se revierte de forma explícita. Independientemente del modo de sesión, se recomienda agregar controladores de excepciones para garantizar que las transacciones se reviertan correctamente lo antes posible y evitar mantener bloqueos y recursos durante más tiempo del necesario.
En el siguiente ejemplo, se muestra un controlador de excepciones que revierte una transacción:
BEGIN BEGIN TRANSACTION; INSERT INTO mydataset.NewArrivals VALUES ('top load washer', 100, 'warehouse #1'); -- Trigger an error. SELECT 1/0; COMMIT TRANSACTION; EXCEPTION WHEN ERROR THEN -- Roll back the transaction inside the exception handler. SELECT @@error.message; ROLLBACK TRANSACTION; END;
Declaraciones admitidas en transacciones
Los tipos de declaraciones siguientes se admiten en las transacciones:
- Declaraciones de consulta:
SELECT - Sentencias DML:
INSERT,UPDATE,DELETE,MERGEyTRUNCATE TABLE Declaraciones DDL en entidades temporales:
CREATE TEMP TABLECREATE TEMP FUNCTIONDROP TABLEen una tabla temporalDROP FUNCTIONen una función temporal
Las declaraciones DDL que crean o descartan entidades permanentes, como conjuntos de datos, tablas y funciones, no son compatibles con las transacciones.
Funciones de fecha y hora en transacciones
En una transacción, las siguientes funciones de fecha y hora tienen comportamientos especiales:
Las funciones
CURRENT_TIMESTAMP,CURRENT_DATEyCURRENT_TIMEmuestran la marca de tiempo de cuando se inició la transacción.No puedes usar la cláusula
FOR SYSTEM_TIME AS OFpara leer una tabla más allá de la marca de tiempo de cuando comenzó la transacción. Si lo haces, se muestra un error.
Ejemplo de una transacción
En este ejemplo, se supone que hay dos tablas llamadas Inventory y NewArrivals, creadas de la siguiente manera:
CREATE OR REPLACE TABLE mydataset.Inventory ( product string, quantity int64, supply_constrained bool ); CREATE OR REPLACE TABLE mydataset.NewArrivals ( product string, quantity int64, warehouse string ); INSERT mydataset.Inventory (product, quantity) VALUES('top load washer', 10), ('front load washer', 20), ('dryer', 30), ('refrigerator', 10), ('microwave', 20), ('dishwasher', 30); INSERT mydataset.NewArrivals (product, quantity, warehouse) VALUES('top load washer', 100, 'warehouse #1'), ('dryer', 200, 'warehouse #2'), ('oven', 300, 'warehouse #1');
La tabla Inventory contiene información sobre el inventario actual, y NewArrivals contiene información sobre los elementos recién llegados.
La siguiente transacción actualiza Inventory con los elementos nuevas y borra los registros correspondientes de NewArrivals. Si suponemos que todas las declaraciones se completan de forma correcta, los cambios en ambas tablas se confirman de forma atómica como una sola transacción.
BEGIN TRANSACTION; -- Create a temporary table that holds new arrivals from 'warehouse #1'. CREATE TEMP TABLE tmp AS SELECT * FROM mydataset.NewArrivals WHERE warehouse = 'warehouse #1'; -- Delete the matching records from the NewArravals table. DELETE mydataset.NewArrivals WHERE warehouse = 'warehouse #1'; -- Merge the records from the temporary table into the Inventory table. MERGE mydataset.Inventory AS I USING tmp AS T ON I.product = T.product WHEN NOT MATCHED THEN INSERT(product, quantity, supply_constrained) VALUES(product, quantity, false) WHEN MATCHED THEN UPDATE SET quantity = I.quantity + T.quantity; -- Drop the temporary table and commit the transaction. DROP TABLE tmp; COMMIT TRANSACTION;
Simultaneidad de las transacciones
Si una transacción actualiza o borra filas en una tabla, la transacción adquiere un bloqueo a nivel de la tabla en lugar de bloquear particiones individuales. Otras transacciones o sentencias DML que mutan filas en la misma tabla no se pueden ejecutar de forma simultánea, incluso si se orientan a diferentes particiones de una tabla particionada. BigQuery cancela las transacciones en conflicto. Sin embargo, BigQuery pone en cola las sentencias DML en conflicto que se ejecutan fuera de una transacción para ejecutarse más tarde, sujetas a los límites de puesta en cola.
Cuando ejecutas una declaración DML de mutación dentro de una transacción de varias sentencias, BigQuery mantiene el bloqueo de escritura en la tabla de destino hasta que la transacción se confirma o se revierte, o hasta que finaliza la consulta o sesión principal de varias sentencias. Este comportamiento se aplica a las transacciones en una consulta de varias instrucciones, un procedimiento almacenado o una sesión activa, como una conexión ODBC o JDBC. BigQuery no libera el bloqueo cuando finaliza la sentencia DML individual. Los cálculos de larga duración en la misma transacción abierta mantienen la tabla bloqueada y hacen que fallen las transacciones de mutación simultáneas en esa tabla.
Las operaciones que leen o agregan filas nuevas pueden ejecutarse de forma simultánea con la transacción. Por ejemplo, cualquiera de las siguientes operaciones se pueden realizar de forma simultánea en una tabla, mientras que una transacción muta los datos en la misma tabla:
- Declaraciones
SELECT - Operaciones de lectura de la API de lectura de almacenamiento de BigQuery
- Consultas de BigQuery BI Engine
- Declaraciones
INSERT - Trabajos de carga que usan la disposición
WRITE_APPENDpara agregar filas - Operaciones de escritura por transmisión
Si una transacción solo lee una tabla o le agrega filas nuevas, cualquier operación se puede
realizar de forma simultánea en esa tabla porque las declaraciones INSERT no
entran en conflicto entre sí. Para evitar que se ejecuten de forma simultánea varias transacciones que, de lo contrario,
solo insertarían filas en una tabla, inicia cada transacción
con una sentencia DELETE que no modifique ninguna fila, como
DELETE FROM TABLE_NAME WHERE FALSE;. Incluir esta
sentencia hace que BigQuery adquiera un bloqueo a nivel de tabla en la
sentencia DELETE, por lo que cualquier otra transacción simultánea que también ejecute una
sentencia de mutación en esa tabla entra en conflicto y se cancela.
Evita y resuelve conflictos de simultaneidad
Para reducir los conflictos de simultaneidad de transacciones, usa las siguientes prácticas:
- Quita los wrappers de transacciones innecesarios: Si un procedimiento almacenado o
una consulta de varias instrucciones ejecuta solo una declaración DML de mutación, como una
sentencia
MERGE, no unas la sentencia en sentenciasBEGIN TRANSACTIONyCOMMIT TRANSACTION. Una sola declaración DML ya es atómica. Ejecutar la sentencia fuera de una transacción de varias sentencias permite que BigQuery aplique la puesta en cola de DML. - Reintenta las transacciones con errores con una retirada exponencial: Cuando una transacción de varias declaraciones falla debido a una actualización simultánea, BigQuery revierte la transacción y libera el bloqueo de la tabla. Debido a que BigQuery puede tardar varios segundos en liberar el bloqueo en la capa de metadatos, vuelve a intentar las transacciones con errores con una estrategia de retirada exponencial. Espera al menos 60 segundos antes del primer reintento.
Visualiza la información de la transacción
BigQuery asigna un ID de transacción a cada transacción de varias declaraciones. El ID de transacción se adjunta a cada consulta que se ejecuta dentro de la transacción. Para ver los ID de transacción de tus trabajos, consulta las vistas INFORMATION_SCHEMA.JOBS* de la columna transaction_id.
Cuando se ejecuta una transacción de varias declaraciones, BigQuery crea un trabajo secundario para cada declaración en la transacción. Para una transacción determinada, cada trabajo secundario asociado con esa transacción tiene el mismo valor transaction_id.
En los siguientes ejemplos, se muestra cómo encontrar información sobre tus transacciones.
Busca todas las transacciones confirmadas o revertidas
La siguiente consulta muestra todas las transacciones que se confirmaron de forma correcta.
SELECT transaction_id, parent_job_id, query FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE statement_type = "COMMIT_TRANSACTION" AND error_result IS NULL;
La siguiente consulta muestra todas las transacciones que se revertiron de forma correcta.
SELECT transaction_id, parent_job_id, query FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE statement_type = "ROLLBACK_TRANSACTION" AND error_result IS NULL;
Encuentra la hora de inicio y finalización de una transacción
La siguiente consulta muestra los tiempos de inicio y finalización para un ID de transacción especificado.
SELECT transaction_id, start_time, end_time, statement_type FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_USER WHERE transaction_id = "TRANSACTION_ID" AND statement_type IN ("BEGIN_TRANSACTION", "COMMIT_TRANSACTION", "ROLLBACK_TRANSACTION") ORDER BY start_time;
Encuentra la transacción en la que se ejecuta un trabajo
La siguiente consulta obtiene la transacción asociada con un ID de trabajo especificado. Muestra NULL si el trabajo no está en ejecución dentro de una transacción de varias declaraciones.
SELECT transaction_id FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE job_id = 'JOB_ID';
Encuentra el trabajo actual que se ejecuta dentro de una transacción
La siguiente consulta muestra información sobre el trabajo que se ejecuta actualmente dentro de una transacción especificada, si existe.
SELECT job_id, query, start_time, total_slot_ms FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE transaction_id = 'TRANSACTION_ID' AND state = RUNNING;
Encuentra las transacciones activas que afectan a una tabla
La siguiente consulta muestra las transacciones activas que afectan a una tabla especificada. Si una transacción activa se ejecuta como parte de consultas de varias sentencias, como dentro de un procedimiento almacenado, también devolverá el ID del trabajo superior. Si la transacción se ejecuta dentro de una sesión, también mostrará la información de la sesión.
WITH running_transactions AS ( SELECT DISTINCT transaction_id FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT EXCEPT DISTINCT SELECT transaction_id FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE statement_type = 'COMMIT_TRANSACTION' OR statement_type = 'ROLLBACK_TRANSACTION' ) SELECT jobs.transaction_id, parent_job_id, session_info, query FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT AS jobs, running_transactions WHERE destination_table = ("PROJECT_NAME", "DATASET_NAME", "TABLE_NAME") AND jobs.transaction_id = running_transactions.transaction_id;
Encuentra las transacciones activas que se ejecutan en una transacción de varias declaraciones
La siguiente consulta muestra las transacciones activas para un trabajo en particular, especificadas por el ID del trabajo que ejecuta la transacción de varias declaraciones.
SELECT DISTINCT transaction_id FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE parent_job_id = "JOB_ID" EXCEPT DISTINCT SELECT transaction_id FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE parent_job_id = "JOB_ID" AND (statement_type = 'COMMIT_TRANSACTION' OR statement_type = 'ROLLBACK_TRANSACTION');
Encuentra trabajos superpuestos para una transacción con errores
Cuando una transacción o una declaración DML falla con un error de actualización simultánea, es posible que una verificación del historial de consultas de las sentencias DML individuales no muestre una sentencia DML activa en el momento de la falla. Esta situación se produce cuando una consulta o sesión de varias instrucciones superior ejecuta una declaración DML anterior dentro de una transacción y sigue ejecutando otras sentencias mientras mantiene el bloqueo de la tabla.
Para las cargas de trabajo entre proyectos, puedes consultar la vista
INFORMATION_SCHEMA.JOBS_BY_ORGANIZATION
en lugar de INFORMATION_SCHEMA.JOBS_BY_PROJECT. En la siguiente consulta, se unen
los trabajos de DML secundarios con sus trabajos superiores en INFORMATION_SCHEMA.JOBS_BY_PROJECT
para identificar los trabajos, las secuencias de comandos o las sesiones mutantes que se superpusieron con un trabajo
con errores:
SELECT child_jobs.job_id, child_jobs.parent_job_id, child_jobs.transaction_id, child_jobs.session_info.session_id, child_jobs.statement_type, child_jobs.start_time AS statement_start_time, child_jobs.end_time AS statement_end_time, parent_jobs.start_time AS parent_start_time, parent_jobs.end_time AS parent_end_time, COALESCE(parent_jobs.start_time, child_jobs.start_time) AS lock_window_start, COALESCE( parent_jobs.end_time, child_jobs.end_time, CURRENT_TIMESTAMP() ) AS lock_window_end, child_jobs.error_result.message AS error_message, child_jobs.query FROM `region-REGION`.INFORMATION_SCHEMA.JOBS_BY_PROJECT AS child_jobs LEFT JOIN `region-REGION`.INFORMATION_SCHEMA.JOBS_BY_PROJECT AS parent_jobs ON child_jobs.parent_job_id = parent_jobs.job_id WHERE child_jobs.creation_time BETWEEN TIMESTAMP_SUB(TIMESTAMP 'START_TIME', INTERVAL 6 HOUR) AND TIMESTAMP_ADD(TIMESTAMP 'END_TIME', INTERVAL 1 HOUR) AND child_jobs.destination_table.project_id = 'PROJECT_ID' AND child_jobs.destination_table.dataset_id = 'DATASET_NAME' AND child_jobs.destination_table.table_id = 'TABLE_NAME' AND child_jobs.statement_type IN ( 'UPDATE', 'DELETE', 'MERGE', 'TRUNCATE_TABLE' ) AND COALESCE(parent_jobs.start_time, child_jobs.start_time) <= TIMESTAMP 'END_TIME' AND COALESCE(parent_jobs.end_time, child_jobs.end_time, CURRENT_TIMESTAMP()) >= TIMESTAMP 'START_TIME' ORDER BY lock_window_start;
Reemplaza lo siguiente:
REGION: Es la región del conjunto de datos (por ejemplo,us).START_TIME: la marca de tiempostart_timedel trabajo con errores (por ejemplo,2026-06-15 10:00:00 UTC).END_TIME: Es la marca de tiempoend_timedel trabajo con errores (por ejemplo,2026-06-15 10:05:00 UTC).PROJECT_ID: Es el ID del proyecto que contiene la tabla de destino.DATASET_NAME: Es el nombre del conjunto de datos que contiene la tabla de destino.TABLE_NAME: Es el nombre de la tabla de destino.
Limitaciones
- Las transacciones no pueden usar declaraciones DDL que afecten a entidades permanentes.
- Dentro de una transacción, las vistas materializadas se interpretan como vistas lógicas. Aunque aún puedes consultar una vista materializada dentro de una transacción, eso no genera ninguna mejora en el rendimiento ni una reducción de costos en comparación con la vista lógica equivalente.
Cuando una transacción con varias declaraciones que falla, se activa una operación de reversión que se encarga de deshacer todos los cambios pendientes así como de excluir los reintentos.
Una transacción puede mutar datos en un máximo de 100 tablas y puede realizar como máximo 100,000 modificaciones de particiones.
BI Engine no acelera las consultas dentro de una transacción.
Los metadatos de las fuentes de datos externas no se pueden actualizar dentro de una transacción con un procedimiento del sistema.