Qual è la differenza tra lettura non ripetibile e lettura fantasma?


155

Qual è la differenza tra lettura non ripetibile e lettura fantasma?

Ho letto l'articolo su Isolation (sistemi di database) da Wikipedia , ma ho qualche dubbio. Nell'esempio seguente, cosa succederà: la lettura non ripetibile e la lettura fantasma ?

Transazione A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
PRODUZIONE:
1----MIKE------29019892---------5000
Transazione B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
Transazione A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1

Un altro dubbio è, nell'esempio sopra, quale livello di isolamento dovrebbe essere usato? E perché?


Risposte:


166

Da Wikipedia (che ha esempi grandi e dettagliati per questo):

Si verifica una lettura non ripetibile, quando nel corso di una transazione viene recuperata una riga due volte e i valori all'interno della riga differiscono tra le letture.

e

Una lettura fantasma si verifica quando, nel corso di una transazione, vengono eseguite due query identiche e la raccolta di righe restituita dalla seconda query è diversa dalla prima.

Esempi semplici:

  • L'utente A esegue la stessa query due volte.
  • Nel mezzo, l'utente B esegue una transazione e si impegna.
  • Lettura non ripetibile: la riga A che l'utente A ha interrogato ha un valore diverso la seconda volta.
  • Lettura fantasma: tutte le righe nella query hanno lo stesso valore prima e dopo, ma sono state selezionate righe diverse (poiché B ne ha eliminato o inserito alcune). Esempio: select sum(x) from table;restituirà un risultato diverso anche se nessuna delle righe interessate è stata aggiornata, se le righe sono state aggiunte o eliminate.

Nell'esempio sopra, quale livello di isolamento utilizzare?

Di quale livello di isolamento hai bisogno dipende dalla tua applicazione. C'è un costo elevato per un livello di isolamento "migliore" (come una concorrenza ridotta).

Nel tuo esempio, non avrai una lettura fantasma, perché selezioni solo da una singola riga (identificata dalla chiave primaria). Puoi avere letture non ripetibili, quindi se questo è un problema, potresti voler avere un livello di isolamento che lo impedisce. In Oracle, la transazione A potrebbe anche emettere un SELEZIONA PER AGGIORNAMENTO, quindi la transazione B non può modificare la riga fino al completamento di A.


6
Non capisco davvero la logica di una tale sintassi ... Una lettura NON ripetibile si verifica quando la lettura viene ripetuta (e si ottiene un valore diverso) ??! ...
serhio

14
@serhio "non ripetibile" si riferisce al fatto che è possibile leggere un valore una volta e ottenere x come risultato, quindi leggere nuovamente e ottenere y come risultato, quindi non è possibile ripetere (non ripetibili) gli stessi risultati da due query separate della stessa riga, poiché quel valore di riga è stato aggiornato tra le letture.
BateTech,

@Thilo Qualunque esempio di caso d'uso reale in cui la lettura ripetibile potrebbe creare problemi e dove è necessario?
user104309,

Cosa succede se il PK viene modificato in un'altra transazione? Ciò potrebbe comportare una lettura fantasma? (Una cosa strana da fare nella maggior parte dei casi, ma non impossibile.)
jpmc26

1
Entrambi sembrano uguali per me
sn.anurag

127

Un modo semplice in cui mi piace pensarci è:

Le letture non ripetibili e fantasma hanno a che fare con le operazioni di modifica dei dati di una transazione diversa, che sono state commesse dopo l'inizio della transazione e quindi lette dalla transazione.

Le letture non ripetibili si verificano quando la tua transazione legge AGGIORNAMENTI impegnati da un'altra transazione. La stessa riga ora ha valori diversi rispetto a quando è iniziata la transazione.

Le letture fantasma sono simili ma durante la lettura da INSERTI impegnati e / o ELIMINA da un'altra transazione. Ci sono nuove righe o righe che sono scomparse da quando hai iniziato la transazione.

Le letture sporche sono simili alle letture non ripetibili e fantasma, ma si riferiscono alla lettura di dati NON COMUNI e si verificano quando viene letto un AGGIORNAMENTO, INSERISCI o ELIMINA da un'altra transazione e l'altra transazione NON ha ancora eseguito il commit dei dati. Sta leggendo i dati "in corso", che potrebbero non essere completi e che non potrebbero mai essere effettivamente impegnati.


4
Ha a che fare con i livelli di isolamento delle transazioni e la concorrenza. Usando il livello di isolamento predefinito, non otterrai letture sporche e, nella maggior parte dei casi, vorrai evitare letture sporche. Esistono livelli di isolamento o suggerimenti di query che consentiranno letture sporche, che in alcuni casi è un compromesso accettabile per ottenere una maggiore concorrenza o è necessario a causa di un caso limite, come la risoluzione dei problemi di una transazione in corso da un'altra connessione. È bene che l'idea di una lettura sporca non superi il "test dell'olfatto" per te, bc come regola generale, dovrebbero essere evitati, ma hanno uno scopo.
BateTech,

1
@PHPAvenger qui è un caso d'uso per il livello di isolamento READ UNCOMMITTED: c'è sempre la possibilità di incontrare un deadlock tra una query select e una query di aggiornamento (spiegata qui ). Se la query di selezione è troppo complessa per creare un indice di copertura, al fine di evitare deadlock, sarà necessario utilizzare un livello di isolamento READ UNCOMMITED con il rischio di incontrare letture sporche, ma con quale frequenza si effettuano rollback delle transazioni per preoccuparsi di quelle letture sporche no essere permanente ?!
petrica.martinescu,

1
@ petrica.martinescu i problemi causati da letture sporche NON riguardano solo il rollback di una transazione. Le letture sporche possono restituire risultati molto imprecisi a seconda di come sono stati modificati i dati nelle transazioni in sospeso. Immagina una transazione che esegua una serie di diverse eliminazioni, aggiornamenti e / o inserti. Se leggi i dati nel mezzo di quella transazione usando "leggi non confermato", sono incompleti. Il livello di isolamento dello snapshot (in SQL Server) è un'alternativa molto migliore alla lettura senza commit. Un caso d'uso valido per leggere il livello di isolamento senza commit in un sistema di produzione è l'IMO raro.
BateTech

2
@DiponRoy ottima domanda. Il blocco implementato se si utilizza l'isolamento ripetibile in lettura (RR) dovrebbe impedire l'eliminazione delle righe selezionate. Nel corso degli anni ho visto diverse definizioni dei 2 livelli iso, principalmente dicendo che phantom è un cambiamento nella raccolta / # righe restituite e RR è la stessa riga che viene modificata. Ho appena controllato la documentazione MS SQL aggiornata che dice che le eliminazioni possono causare non-RR ( docs.microsoft.com/en-us/sql/odbc/reference/develop-app/… ) quindi penso che sarebbe sicuro raggruppare le eliminazioni in anche la categoria RR
BateTech,

2
@anir yes inserimenti ed eliminazioni sono inclusi nelle letture sporche. Esempio: avvia una transazione, inserisci 2 delle 100 righe di fattura sulla connessione a, ora la connessione b legge quelle 2 righe prima che venga eseguito il commit del trx e prima che vengano aggiunte le altre 98 righe, quindi non include tutte le informazioni per la fattura. Questa sarebbe una lettura sporca che coinvolge un inserto.
BateTech,

28

Come spiegato in questo articolo , l' anomalia di lettura non ripetibile si presenta come segue:

inserisci qui la descrizione dell'immagine

  1. Alice e Bob avviano due transazioni di database.
  2. Bob legge il record del post e il valore della colonna del titolo è Transazioni.
  3. Alice modifica il titolo di un determinato record di post sul valore di ACID.
  4. Alice esegue la transazione del database.
  5. Se Bob rilegge il record del post, osserverà una versione diversa di questa riga della tabella.

In questo articolo su Phantom Read , puoi vedere che questa anomalia può verificarsi come segue:

inserisci qui la descrizione dell'immagine

  1. Alice e Bob avviano due transazioni di database.
  2. Bob legge tutti i record post_comment associati alla riga post con il valore identificativo di 1.
  3. Alice aggiunge un nuovo record post_comment associato alla riga di post con il valore identificativo di 1.
  4. Alice esegue la transazione del database.
  5. Se Bob rilegge i record post_comment con il valore della colonna post_id uguale a 1, osserverà una versione diversa di questo set di risultati.

Pertanto, mentre la lettura non ripetibile si applica a una singola riga, la lettura fantasma riguarda un intervallo di record che soddisfano determinati criteri di filtro delle query.


3
visualizzazione superba @Vlad
dextermini il

23

Leggi i fenomeni

  • Letture sporche : leggi i dati NON COMPRESI da un'altra transazione
  • Letture non ripetibili : leggi i dati COMMITTATI da unaUPDATEquery da un'altra transazione
  • Phantom legge : legge i dati COMMITTATI da unaqueryINSERToDELETEda un'altra transazione

Nota : le istruzioni DELETE di un'altra transazione hanno anche una probabilità molto bassa di causare letture non ripetibili in alcuni casi. Accade quando purtroppo l'istruzione DELETE rimuove la stessa riga su cui stava eseguendo la query della transazione corrente. Ma questo è un caso raro e molto più improbabile che si verifichi in un database che ha milioni di righe in ogni tabella. Le tabelle contenenti i dati delle transazioni di solito hanno un volume di dati elevato in qualsiasi ambiente di produzione.

Inoltre, possiamo osservare che gli AGGIORNAMENTI possono essere un lavoro più frequente nella maggior parte dei casi d'uso piuttosto che INSERIRE o ELIMINA effettivi (in questi casi, il pericolo di letture non ripetibili rimane solo - le letture fantasma non sono possibili in quei casi). Questo è il motivo per cui gli AGGIORNAMENTI vengono trattati in modo diverso da INSERT-DELETE e anche l'anomalia risultante viene denominata in modo diverso.

Vi è anche un costo di elaborazione aggiuntivo associato alla gestione di INSERT-DELETE, piuttosto che alla semplice gestione degli AGGIORNAMENTI.


Vantaggi di diversi livelli di isolamento

  • READ_UNCOMMITTED impedisce nulla. È il livello di isolamento zero
  • READ_COMMITTED impedisce solo uno, ovvero letture sporche
  • REPEATABLE_READ previene due anomalie: letture sporche e letture non ripetibili
  • SERIALIZZABILE previene tutte e tre le anomalie: letture sporche, letture non ripetibili e letture Phantom

Allora perché non impostare semplicemente la transazione SERIALIZZABILE in ogni momento? Bene, la risposta alla domanda sopra è: L'impostazione SERIALIZZABILE rende le transazioni molto lente , che di nuovo non vogliamo.

In effetti il ​​consumo di tempo di transazione è nel seguente tasso:

SERIALIZZABILE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED

Quindi l'impostazione READ_UNCOMMITTED è la più veloce .


Sommario

In realtà dobbiamo analizzare il caso d'uso e decidere un livello di isolamento in modo da ottimizzare i tempi di transazione e prevenire anche la maggior parte delle anomalie.

Si noti che i database per impostazione predefinita hanno l'impostazione REPEATABLE_READ.


1
UPDATE o DELETE possono entrambi avvenire per letture non ripetibili o è solo UPDATE?
Dipon Roy,

1
AGGIORNARE o ELIMINARE possono avvenire entrambi per letture non ripetibili
niket patel,

In realtà possiamo riassumere che in media un'istruzione DELETE casuale eseguita da un'altra transazione sullo stesso database ha una probabilità molto bassa di causare letture non ripetibili per la transazione corrente. Ma la stessa dichiarazione di eliminazione ha il 100% di probabilità di causare una lettura Phantom per la transazione corrente. In questo modo, la mia scrittura è un po 'sbagliata se la prendi parola per parola. Ma hey, l'ho scritto intenzionalmente in questo modo per rendere le cose più chiare al lettore.
Subhadeep Ray

+1 per una spiegazione semplice e di facile comprensione. Tuttavia, penso che la maggior parte dei database (oracle, mysql) abbia un livello di isolamento predefinito di Read Committed e probabilmente postgress usa il default di repeatable_read
akila

7

C'è una differenza nell'implementazione tra questi due tipi di livelli di isolamento.
Per "lettura non ripetibile", è necessario il blocco delle righe.
Per "lettura fantasma" , è necessario il blocco con ambito, anche un blocco tabella.
Siamo in grado di implementare questi due livelli utilizzando il protocollo di blocco a due fasi .


Per implementare la lettura ripetibile o serializzabile, non è necessario utilizzare il blocco delle righe.
a_horse_with_no_name

5

In un sistema con letture non ripetibili, il risultato della seconda query della Transazione A rifletterà l'aggiornamento nella Transazione B: vedrà il nuovo importo.

In un sistema che consente letture fantasma, se la Transazione B dovesse inserire una nuova riga con ID = 1, la Transazione A vedrà la nuova riga quando viene eseguita la seconda query; cioè le letture fantasma sono un caso speciale di letture non ripetibili.


Non penso che la spiegazione di una lettura fantasma sia corretta. È possibile ottenere letture fantasma anche se i dati di non commit non sono mai visibili. Vedi l'esempio su Wikipedia (collegato nei commenti sopra).
Thilo,

1

La risposta accettata indica soprattutto che la cosiddetta distinzione tra i due in realtà non è affatto significativa.

Se "una riga viene recuperata due volte e i valori all'interno della riga differiscono tra le letture", allora non sono la stessa riga (non la stessa tupla nel linguaggio RDB corretto) e quindi per definizione è anche il caso che "la raccolta di le righe restituite dalla seconda query sono diverse dalla prima ".

Per quanto riguarda la domanda "quale livello di isolamento dovrebbe essere usato", più i tuoi dati sono di vitale importanza per qualcuno, da qualche parte, più sarà il caso che Serializable sia la tua unica opzione ragionevole.


0

Penso che ci siano alcune differenze tra lettura non ripetibile e lettura fantasma.

Il Non ripetibile significa che ci sono transazioni di rimorchio A e B. se B può notare la modifica di A, quindi forse può capitare di leggere, quindi facciamo notare a B la modifica di A dopo aver commesso.

C'è un nuovo problema: lasciamo che B noti la modifica di A dopo il commit di A, significa che A modifica un valore di riga che detiene la B, a volte B leggerà di nuovo la riga, quindi B otterrà un nuovo valore diverso con la prima volta che ottenere, lo chiamiamo non ripetibile, per affrontare il problema, lasciamo che B ricordi qualcosa (perché non so ancora cosa verrà ricordato) quando B inizia.

Pensiamo alla nuova soluzione, possiamo notare che c'è anche un nuovo problema, perché lasciamo ricordare a B qualcosa, quindi qualunque cosa sia successa in A, la B non può essere influenzata, ma se B vuole inserire alcuni dati nella tabella e B controlla la tabella per assicurarti che non ci siano record, ma questi dati sono stati inseriti da A, quindi potrebbe verificarsi un errore. Lo chiamiamo Phantom-read.


0

la lettura non ripetibile è un livello di isolamento e la lettura fantasma (lettura del valore commesso da altre transazioni) è un concetto (tipo di lettura, ad esempio lettura sporca o lettura istantanea). Il livello di isolamento della lettura non ripetibile consente la lettura fantasma ma non le letture sporche o le istantanee.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.