Ciao a tutti. Vladislav Rodin è in contatto. Attualmente sono il Course Leader per il corso High Workload Architect presso OTUS e insegno anche corsi di architettura software.
Oltre all’insegnamento, come avrai notato, sto scrivendo materiale originale per il blog OTUS su Habré e voglio far coincidere l’articolo di oggi in concomitanza con il lancio del corso , le cui iscrizioni sono aperte proprio adesso.

Introduzione
В abbiamo parlato del fatto che le transazioni nei database servono a risolvere due problemi: garantire la tolleranza agli errori e l'accesso ai dati in un ambiente competitivo. Per eseguire completamente queste attività, la transazione deve avere proprietà ACID. Oggi parleremo in dettaglio della lettera Io (isolamento) in questa abbreviazione.
Isolamento
L’isolamento risolve il problema dell’accesso ai dati in un ambiente competitivo, fornendo essenzialmente protezione dalle condizioni di competizione. Idealmente, isolamento significa serializzazione, ovvero una proprietà che garantisce che il risultato dell'esecuzione delle transazioni in parallelo sia lo stesso che se fossero eseguite in sequenza. Il problema principale con questa proprietà è che è molto difficile da fornire tecnicamente e, di conseguenza, ha un impatto significativo sulle prestazioni del sistema. Ecco perché l’isolamento viene spesso indebolito, accettando il rischio di alcune anomalie, di cui parleremo più avanti. La possibilità del verificarsi di determinate anomalie caratterizza proprio il livello di isolamento delle transazioni.
Le anomalie più conosciute sono: lettura sporca, lettura non ripetibile, lettura fantasma, ma in realtà ce ne sono altre 5: scrittura sporca, aggiornamento perso cursore, aggiornamento perso, lettura skew, scrittura skew.
Scrittura sporca
L'essenza dell'anomalia è che le transazioni possono sovrascrivere i dati non impegnati.

Questa anomalia è pericolosa non solo perché i dati possono entrare in conflitto dopo aver effettuato entrambe le transazioni (come nell'immagine), ma anche perché viene violata l'atomicità: poiché consentiamo la sovrascrittura dei dati non impegnati, non è chiaro come ripristinare una transazione senza influenzarne un'altra .
L’anomalia può essere risolta in modo molto semplice: attacchiamo un blocco al record prima di iniziare la registrazione, impedendo ad altre transazioni di modificare il record finché il blocco non viene rimosso.
Lettura sporca
Lettura sporca significa leggere dati non impegnati.

I problemi sorgono quando è necessario prendere azioni o decisioni sulla base del campione.
Per correggere l'anomalia è possibile allegare un blocco di lettura, ma ciò avrà un notevole impatto sulle prestazioni. È molto più semplice dire che per un'operazione di rollback, lo stato iniziale dei dati (prima dell'inizio della registrazione) deve essere salvato nel sistema. Perché non leggere da lì? È abbastanza economico da consentire alla maggior parte dei database di rimuovere la lettura sporca per impostazione predefinita.
Aggiornamento perso
Aggiornamento perso significa aggiornamenti persi e la traduzione riflette in modo abbastanza accurato l'essenza del problema:

In effetti, il risultato della transazione T2 è stato annullato. Questa situazione può essere corretta mediante blocchi di scrittura espliciti o impliciti. Cioè, aggiorniamo semplicemente il record e quindi si verifica un blocco implicito oppure eseguiamo seleziona per aggiornare, provocando il verificarsi di un blocco di lettura e scrittura. Tieni presente che un'operazione del genere è piuttosto pericolosa: con la nostra lettura “innocente” blocchiamo altre letture. Alcuni database offrono servizi più sicuri seleziona per condividere, consentendo la lettura ma non la modifica dei dati.
Aggiornamento del cursore perso
Per un controllo più preciso, le basi possono offrire altri strumenti, come un cursore. Un cursore è una struttura che contiene un insieme di righe e consente di scorrere su di esse. dichiarare nome_cursore per istruzione_selezionata. Il contenuto del cursore è descritto da select.
Perché hai bisogno di un cursore? Il fatto è che alcuni database offrono un blocco su tutti i record selezionati tramite select (stabilità di lettura) o solo sul record su cui si trova attualmente il cursore (stabilità del cursore). Con la stabilità del cursore, viene implementato il blocco breve, che ci consente di ridurre il numero di blocchi se iteriamo su un ampio campione di dati. Pertanto, l'anomalia dell'aggiornamento perso viene isolata separatamente per il cursore.
Lettura non ripetibile
La lettura non ripetibile è che durante l'esecuzione della nostra transazione, 2 letture consecutive dello stesso record porteranno a risultati diversi, perché un'altra transazione è intervenuta tra queste due letture, ha cambiato i nostri dati ed è stata confermata.

Perché questo è un problema? Immagina che l'obiettivo della transazione T2 nella figura sia selezionare tutti i beni il cui prezzo è inferiore a 150 USD. Qualcun altro ha aggiornato il prezzo a $ 200. Pertanto, il filtro installato non ha funzionato.
Queste anomalie cessano di verificarsi quando si aggiungono gli interblocchi bifase o quando si utilizza il meccanismo MVCC, di cui vorrei parlare a parte.
Lettura fantasma
Phantom è una lettura di dati aggiunti da un'altra transazione.

Ad esempio, possiamo osservare l'errata selezione del prodotto più economico quando si verifica questa anomalia.
Liberarsi delle letture fantasma è già abbastanza difficile. Il blocco regolare non è sufficiente, perché non possiamo bloccare qualcosa che ancora non esiste. I sistemi 2PL utilizzano il blocco predittivo, mentre i sistemi MVCC dispongono di uno scheduler delle transazioni che ripristina le transazioni che potrebbero essere interrotte da un inserimento. Sia il primo che il secondo meccanismo sono piuttosto pesanti.
Leggi inclinato
Lo spostamento di lettura si verifica quando lavoriamo con più tabelle, il cui contenuto deve cambiare in modo coerente.
Diciamo che abbiamo tabelle che rappresentano i post e le loro meta informazioni:

Una transazione legge dalle tabelle, l'altra le modifica:

Come risultato della transazione T1, il post ha titolo = Buono e aggiornato_by = T2, il che rappresenta una sorta di incoerenza.
In realtà si tratta di una lettura non ripetibile, ma facente parte di più tabelle.
Per risolvere questo problema, T1 può bloccare tutte le righe che leggerà, impedendo alla transazione T2 di modificare le informazioni. In caso di MVCC, la transazione T2 verrà annullata. La protezione contro questa anomalia può diventare importante se utilizziamo i cursori.
Scrivi in modo obliquo
Questa anomalia è anche più semplice da spiegare con un esempio: supponiamo che nel nostro ordinamento almeno un medico debba essere in servizio, ma entrambi i medici decidano di annullare il proprio servizio:


L'anomalia faceva sì che nessuno dei medici sarebbe stato in servizio. Perché è successo questo? Perché la transazione stava verificando una condizione che avrebbe potuto essere violata da un'altra transazione e, a causa dell'isolamento, non abbiamo riscontrato questo cambiamento.
Questa è la stessa lettura non ripetibile. In alternativa, le selezioni possono inserire blocchi su questi record.
L'inclinazione di scrittura e l'inclinazione di lettura sono combinazioni delle anomalie precedenti. Puoi considerare l'inclinazione della scrittura, che è essenzialmente una lettura fantasma. Considera una tabella che contiene i nomi dei dipendenti, i loro stipendi e il progetto su cui lavorano:


Di conseguenza, otteniamo il seguente quadro: ogni manager pensava che il suo cambiamento non avrebbe portato al superamento del budget, quindi ha apportato modifiche al personale che, nel complesso, hanno portato a un superamento dei costi.
La causa del problema è esattamente la stessa della lettura fantasma.
risultati
Rilassare il livello di isolamento delle transazioni nel database è un compromesso tra sicurezza e prestazioni; la scelta di questo livello dovrebbe essere affrontata in base ai potenziali rischi per l'azienda se si verificano determinate anomalie.
Fonte: habr.com
