Isolamento serializzabile - Amazon Redshift

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Isolamento serializzabile

Alcune applicazioni richiedono non solo query e caricamento simultanei, ma anche la possibilità di scrivere simultaneamente su più tabelle o sulla stessa tabella. In questo contesto, simultaneamente significa una sovrapposizione non pianificata per l'esecuzione simultanea. Due transazioni sono considerate simultanee se la seconda inizia prima del primo commit. Le operazioni simultanee possono provenire da sessioni diverse controllate dallo stesso utente o da utenti diversi.

Nota

Amazon Redshift supporta un comportamento di commit automatico di default in cui viene eseguito singolarmente il commit di ogni comando SQL eseguito separatamente. Se si racchiude un set di comandi in un blocco di transazione (definito dalle istruzioni BEGIN e END), viene eseguito il commit del blocco come una transazione, quindi è possibile eseguirne il rollback se necessario. Eccezioni a questo comportamento sono i comandi TRUNCATE e VACUUM, che eseguono automaticamente il commit di tutte le modifiche in sospeso apportate nella transazione corrente.

Alcuni client SQL eseguono automaticamente i comandi BEGIN e COMMIT, pertanto il client controlla se un gruppo di istruzioni viene eseguito come transazione o se ogni singola istruzione viene eseguita come transazione propria. Controlla la documentazione per l'interfaccia che stai utilizzando. Ad esempio, quando si utilizza il driver JDBC di Amazon Redshift, un'istruzione JDBC PreparedStatement con una stringa di query che contiene più comandi SQL (separati da punto e virgola) esegue tutte le istruzioni come una singola transazione. Al contrario, se si utilizza SQL Workbench/J e si imposta AUTO COMMIT ON, quindi se si eseguono più istruzioni, ogni istruzione viene eseguita come transazione propria.

Le operazioni di scrittura simultanee sono supportate in Amazon Redshift in modo protettivo utilizzando i blocchi di scrittura sulle tabelle e il principio di isolamento serializzabile. L'isolamento serializzabile mantiene l'illusione che una transazione in esecuzione su una tabella sia l'unica transazione in esecuzione su quella tabella. Ad esempio, due transazioni in esecuzione simultanea, T1 e T2, devono produrre gli stessi risultati di almeno uno dei seguenti esempi:

  • T1 e T2 vengono eseguite in serie in questo ordine

  • T2 e T1 vengono eseguite in serie in questo ordine

Le transazioni simultanee sono invisibili l'una all'altra; non possono rilevare le reciproche modifiche. Ogni transazione simultanea creerà una snapshot del database all'inizio della transazione. Una snapshot del database viene creata all'interno di una transazione alla prima occorrenza della maggior parte delle istruzioni SELECT, dei comandi DML come COPY, DELETE, INSERT, UPDATE e TRUNCATE e dei seguenti comandi DDL:

  • ALTER TABLE (per aggiungere o eliminare colonne)

  • CREATE TABLE

  • DROP TABLE

  • TRUNCATE TABLE

Se qualsiasi esecuzione seriale delle transazioni simultanee produce gli stessi risultati della loro esecuzione simultanea, tali transazioni sono considerate "serializzabili" e possono essere eseguite in modo sicuro. Se nessuna esecuzione seriale di tali transazioni produce gli stessi risultati, la transazione che esegue un'istruzione che potrebbe interrompere la serializzabilità viene arrestata e ne viene eseguito il rollback.

Le tabelle del catalogo di sistema (PG) e altre tabelle di sistema Amazon Redshift (STL e STV) non sono bloccate in una transazione. Di conseguenza, le modifiche agli oggetti di database che derivano dalle operazioni di DDL e TRUNCATE sono visibili al commit in qualsiasi transazione simultanea.

Ad esempio, supponiamo che la tabella A esiste nel database quando iniziano due transazioni simultanee, T1 e T2. Supponiamo che T2 restituisca un elenco di tabelle selezionandole dalla tabella catalogo PG_TABLES. Quindi T1 rilascia la tabella A ed esegue il commit, quindi T2 elenca nuovamente le tabelle. La tabella A non è più elencata. Se T2 prova a eseguire una query sulla tabella rilasciata, Amazon Redshift restituisce un errore di relazione inesistente. La query di catalogo che restituisce l'elenco di tabelle a T2 o verifica che la tabella A esista non è soggetta alle stesse regole di isolamento delle operazioni sulle tabelle utente.

Le transazioni per gli aggiornamenti a queste tabelle vengono eseguite in modalità di isolamento con lettura sottoposta al commit. Le tabelle del catalogo dei prefissi PG non supportano l'isolamento dello snapshot.

Isolamento serializzabile per tabelle di sistema e tabelle di catalogo

Uno snapshot del database viene creato in una transazione per qualsiasi query SELECT che fa riferimento a una tabella creata dall'utente o a una tabella di sistema Amazon Redshift (STL or STV). Le query SELECT che non fanno riferimento ad alcuna tabella non creano un nuovo snapshot del database delle transazioni. Le istruzioni INSERT, DELETE e UPDATE che operano esclusivamente sulle tabelle del catalogo di sistema (PG) non creano un nuovo snapshot del database delle transazioni.

Come correggere errori di isolamento serializzabile

ERROR:1023 DETAIL: violazione di isolamento serializzabile su una tabella in Redshift

Quando Amazon Redshift rileva un errore di isolamento serializzabile, compare un messaggio di errore simile al seguente.

ERROR:1023 DETAIL: Serializable isolation violation on table in Redshift

Per risolvere un errore di isolamento serializzabile, si possono tentare i seguenti metodi:

  • Riprovare la transazione annullata.

    Amazon Redshift ha rilevato che un carico di lavoro simultaneo non è serializzabile. Suggerisce lacune nella logica dell'applicazione, che di solito possono essere risolte provando a eseguire di nuovo la transazione che ha riscontrato l'errore. Se il problema persiste, provare uno degli altri metodi.

  • Spostare al di fuori della transazione tutte le operazioni che non devono essere nella stessa transazione atomica.

    Questo metodo si applica quando singole operazioni all'interno di due transazioni fanno riferimento reciprocamente in modo tale da influire sul risultato dell'altra transazione. Ad esempio, ciascuna delle seguenti due sessioni avvia una transazione.

    Session1_Redshift=# begin;
    Session2_Redshift=# begin;

    Il risultato di un'istruzione SELECT in una delle transazioni potrebbe essere compromesso da un'istruzione INSERT nell'altra. In altre parole, si presuppone che le seguenti istruzioni vengano eseguite in serie, in qualunque ordine. In ogni caso, il risultato è che una delle istruzioni SELECT restituisce una riga in più rispetto all'esecuzione simultanea delle transazioni. Non esiste un ordine in cui le operazioni in serie possono produrre lo stesso risultato dell'esecuzione simultanea. Di conseguenza, l'ultima operazione eseguita genera un errore di isolamento serializzabile.

    Session1_Redshift=# select * from tab1; Session1_Redshift=# insert into tab2 values (1);
    Session2_Redshift=# insert into tab1 values (1); Session2_Redshift=# select * from tab2;

    In molti casi il risultato delle istruzioni SELECT non è importante. In altre parole, l'atomicità delle operazioni nelle transazioni non è importante. In questi casi, occorre spostare le istruzioni SELECT al di fuori delle transazioni, come illustrato nei seguenti esempi.

    Session1_Redshift=# begin; Session1_Redshift=# insert into tab1 values (1) Session1_Redshift=# end; Session1_Redshift=# select * from tab2;
    Session2_Redshift # select * from tab1; Session2_Redshift=# begin; Session2_Redshift=# insert into tab2 values (1) Session2_Redshift=# end;

    In questi esempi non ci sono riferimenti reciproci nelle transazioni. Le due istruzioni INSERT non si compromettono reciprocamente. In questi esempi c'è almeno un ordine in cui le transazioni possono essere eseguite in serie producendo lo stesso risultato dell'esecuzione simultanea. Ciò vuol dire che le transazioni sono serializzabili.

  • Forzare la serializzazione bloccando tutte le tabelle in ciascuna sessione.

    Il comando LOCK blocca le operazioni che possono generare errori di isolamento serializzabile. Quando utilizzi il comando LOCK, ricorda di fare quanto segue:

    • Bloccare tutte le tabelle interessate dalla transazione, incluse quelle interessate dalle istruzioni SELECT di sola lettura all'interno della transazione.

    • Bloccare le tabelle nello stesso ordine, indipendentemente da quello in cui vengono eseguite le operazioni.

    • Bloccare tutte le tabelle all'inizio delle transazione, prima di eseguire qualunque operazione.

  • Utilizzo dell'isolamento degli snapshot per le transazioni simultanee

    Utilizza un comando ALTER DATABASE con isolamento degli snapshot. Per ulteriori informazioni sul parametro SNAPSHOT per ALTER DATABASE, consulta Parametri.

ERROR:1018 DETAIL: la relazione non esiste

Quando le operazioni simultanee di Amazon Redshift vengono eseguite in sessioni diverse, viene visualizzato un messaggio di errore simile al seguente.

ERROR: 1018 DETAIL: Relation does not exist.

Le transazioni in Amazon Redshift seguono l'isolamento degli snapshot. Dopo l'inizio di una transazione, Amazon Redshift acquisisce uno snapshot del database. Per l'intero ciclo di vita della transazione, la transazione opera sullo stato del database come indicato nello snapshot. Se la transazione legge da una tabella che non esiste nello snapshot, genera il messaggio di errore 1018 mostrato in precedenza. Anche quando un'altra transazione simultanea crea una tabella dopo che la transazione ha acquisito lo snapshot, la transazione non può leggere dalla tabella appena creata.

Per risolvere questo errore di isolamento della serializzazione, è possibile provare a spostare l'inizio della transazione in un punto in cui si sa che la tabella esiste.

Se la tabella viene creata da un'altra transazione, questo punto è almeno dopo il commit della transazione. Inoltre, assicurarsi che non sia stata eseguita alcuna transazione simultanea che potrebbe aver eliminato la tabella.

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session2 = # BEGIN;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # SELECT * FROM A;

Di conseguenza, l'ultima operazione eseguita come operazione di lettura da session2 genera un errore di isolamento serializzabile. Questo errore si verifica quando session2 esegue uno snapshot e la tabella è già stata eliminata da una sessione di commit 1. In altre parole, anche se una session3 simultanea ha creato la tabella, session2 non vede la tabella perché non è nello snapshot.

Per risolvere questo errore, è possibile ordinare nuovamente le sessioni come segue.

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # BEGIN; session2 = # SELECT * FROM A;

Ora, quando session2 effettua il suo snapshot, per session3 è già stato eseguito il commit e la tabella è nel database. Session2 può leggere dalla tabella senza alcun errore.