Transazioni multi-istruzione

BigQuery supporta transazioni multi-istruzione all'interno di una singola query o in più query. Una transazione con più istruzioni consente di eseguire operazioni di mutazione, come l'inserimento o l'eliminazione di righe in una o più tabelle, nonché il commit o il rollback delle modifiche a livello atomico.

Gli utilizzi per le transazioni con più dichiarazioni includono:

  • Esecuzione di mutazioni DML su più tabelle come una singola transazione. Le tabelle possono abbracciare più set di dati o progetti.
  • Esecuzione di mutazioni su una singola tabella in più fasi, sulla base di calcoli intermedi.

Le transazioni garantiscono le proprietà ACID e supportano l'isolamento degli snapshot. Durante una transazione, tutte le letture restituiscono uno snapshot coerente delle tabelle a cui viene fatto riferimento nella transazione. Se un'istruzione in una transazione modifica una tabella, le modifiche sono visibili nelle istruzioni successive all'interno della stessa transazione.

Ambito della transazione

Una transazione deve essere contenuta in una singola query SQL, tranne nei casi in cui si trova in Session mode. Una query può contenere più transazioni, ma queste non possono essere nidificate. Puoi eseguire transazioni con più dichiarazioni su più query in una sessione.

Per avviare una transazione, utilizza l'istruzione BEGIN TRANSACTION. La transazione termina quando si verifica una delle seguenti condizioni:

  • La query esegue un'istruzione COMMIT TRANSACTION. Questa istruzione esegue il commit atomico di tutte le modifiche apportate all'interno della transazione.
  • La query esegue un'istruzione ROLLBACK TRANSACTION. Questa istruzione abbandona tutte le modifiche apportate alla transazione.
  • La query termina prima di raggiungere una di queste due istruzioni. In questo caso, BigQuery esegue automaticamente il rollback della transazione.

Se si verifica un errore durante una transazione e la query ha un gestore di eccezioni, BigQuery trasferisce il controllo al gestore delle eccezioni. All'interno del blocco delle eccezioni, puoi scegliere se eseguire il commit o il rollback della transazione.

Se si verifica un errore durante una transazione e non esiste un gestore di eccezioni, la query non riesce e BigQuery esegue automaticamente il rollback della transazione.

L'esempio seguente mostra un gestore di eccezioni che esegue il rollback di una transazione:

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;

Estratti conto supportati nelle transazioni

Nelle transazioni sono supportati i seguenti tipi di istruzioni:

  • Istruzioni query: SELECT
  • Istruzioni DML: INSERT, UPDATE, DELETE, MERGE e TRUNCATE TABLE
  • Istruzioni DDL sulle entità temporanee:

    • CREATE TEMP TABLE
    • CREATE TEMP FUNCTION
    • DROP TABLE su una tabella temporanea
    • DROP FUNCTION su una funzione temporanea

Le istruzioni DDL che creano o eliminano entità permanenti, come set di dati, tabelle e funzioni, non sono supportate all'interno delle transazioni.

Funzioni di data/ora nelle transazioni

All'interno di una transazione, le seguenti funzioni di data/ora presentano comportamenti speciali:

Esempio di transazione

Questo esempio presuppone che esistano due tabelle denominate Inventory e NewArrivals, create come segue:

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 tabella Inventory contiene informazioni sull'inventario corrente, mentre NewArrivals contiene informazioni sugli articoli appena arrivati.

La seguente transazione aggiorna Inventory con i nuovi arrivi ed elimina i record corrispondenti da NewArrivals. Supponendo che tutte le istruzioni siano state completate correttamente, il commit delle modifiche in entrambe le tabelle viene eseguito atomicamente come una singola transazione.

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;

Contemporaneità delle transazioni

Se una transazione muta (aggiorna o elimina) righe in una tabella, non possono essere eseguite contemporaneamente altre transazioni o istruzioni DML che modificano le righe nella stessa tabella. Le transazioni in conflitto vengono annullate. Le istruzioni DML in conflitto che vengono eseguite al di fuori di una transazione vengono messe in coda per essere eseguite in un secondo momento, nel rispetto dei limiti di coda.

Le operazioni che leggono o aggiungono nuove righe possono essere eseguite contemporaneamente alla transazione. Ad esempio, una qualsiasi delle seguenti operazioni può essere eseguita contemporaneamente su una tabella mentre una transazione cambia i dati nella stessa tabella:

  • SELECT estratti conto
  • Operazioni di lettura dell'API BigQuery Storage Read
  • Query da BigQuery BI Engine
  • INSERT estratti conto
  • Job di caricamento che utilizzano l'istruzione WRITE_APPEND per aggiungere righe
  • Operazioni di scrittura flussi

Se una transazione legge solo una tabella o vi aggiunge nuove righe, qualsiasi operazione può essere eseguita contemporaneamente su quella tabella.

Visualizzare le informazioni sulle transazioni

BigQuery assegna un ID transazione a ogni transazione multi-istruzione. L'ID transazione è associato a ogni query eseguita all'interno della transazione. Per visualizzare gli ID transazione dei job, esegui una query sulle visualizzazioni INFORMATION_SCHEMA.JOBS* per la colonna transaction_id.

Quando viene eseguita una transazione multi-istruzione, BigQuery crea un job figlio per ogni istruzione della transazione. Per una determinata transazione, ogni job figlio associato alla transazione ha lo stesso valore transaction_id.

I seguenti esempi mostrano come trovare informazioni sulle tue transazioni.

Trova tutte le transazioni di cui è stato eseguito il commit o il rollback

La seguente query restituisce tutte le transazioni per cui è stato eseguito il commit.

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 seguente query restituisce tutte le transazioni di cui è stato eseguito il rollback.

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;

Trovare l'ora di inizio e di fine di una transazione

La seguente query restituisce l'ora di inizio e di fine per un ID transazione specificato.

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;

Trovare la transazione in cui è in esecuzione un job

La seguente query ottiene la transazione associata a un ID job specificato. Restituisce NULL se il job non è in esecuzione all'interno di una transazione multi-istruzione.

SELECT transaction_id
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE job_id = 'JOB_ID';

Trova il job corrente in esecuzione all'interno di una transazione

La seguente query restituisce informazioni sul job attualmente in esecuzione all'interno di un'eventuale transazione specificata.

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;

Trovare le transazioni attive che interessano una tabella

La seguente query restituisce le transazioni attive che interessano una tabella specificata. Per ogni transazione attiva, se è in esecuzione nell'ambito di query con più istruzioni, ad esempio all'interno di una stored procedure, restituisce anche l'ID job padre. Se la transazione è in esecuzione all'interno di una sessione, restituisce anche le informazioni sulla sessione.

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;

Trova le transazioni attive in esecuzione in una transazione con più istruzioni

La seguente query restituisce le transazioni attive per un particolare job, specificate dall'ID del job che esegue la transazione multi-istruzione.

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

Limitazioni

  • Per le transazioni non è possibile utilizzare istruzioni DDL che interessano entità permanenti.
  • All'interno di una transazione, le viste materializzate sono interpretate come viste logiche. Puoi comunque eseguire query su una vista materializzata all'interno di una transazione, ma ciò non comporta alcun miglioramento delle prestazioni o riduzione dei costi rispetto alla vista logica equivalente.
  • Una transazione con più istruzioni non va a buon fine attiva un'operazione di rollback, annullando tutte le modifiche in attesa e impedendo i nuovi tentativi.

  • Una transazione può mutare i dati in al massimo 100 tabelle e può eseguire al massimo 100.000 modifiche alle partizioni.

  • BI Engine non accelera le query all'interno di una transazione.