Quelle est la différence entre la lecture non répétable et la lecture fantôme?


155

Quelle est la différence entre la lecture non répétable et la lecture fantôme?

J'ai lu l'article Isolation (systèmes de base de données) de Wikipedia , mais j'ai quelques doutes. Dans l'exemple ci-dessous, que va-t-il se passer: la lecture non répétable et la lecture fantôme ?

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

Un autre doute est, dans l'exemple ci-dessus, quel niveau d'isolement doit être utilisé? Et pourquoi?


Réponses:


166

De Wikipédia (qui a des exemples intéressants et détaillés pour cela):

Une lecture non répétable se produit lorsque, au cours d'une transaction, une ligne est récupérée deux fois et que les valeurs de la ligne diffèrent entre les lectures.

et

Une lecture fantôme se produit lorsque, au cours d'une transaction, deux requêtes identiques sont exécutées et que la collection de lignes renvoyée par la deuxième requête est différente de la première.

Exemples simples:

  • L'utilisateur A exécute la même requête deux fois.
  • Entre les deux, l'utilisateur B exécute une transaction et s'engage.
  • Lecture non répétable: la ligne A que l'utilisateur A a interrogée a une valeur différente la deuxième fois.
  • Lecture fantôme: toutes les lignes de la requête ont la même valeur avant et après, mais différentes lignes sont sélectionnées (car B en a supprimé ou inséré). Exemple: select sum(x) from table;renvoie un résultat différent même si aucune des lignes affectées n'a été mise à jour, si des lignes ont été ajoutées ou supprimées.

Dans l'exemple ci-dessus, quel niveau d'isolement utiliser?

Le niveau d'isolement dont vous avez besoin dépend de votre application. Il y a un coût élevé pour un «meilleur» niveau d'isolement (comme une simultanéité réduite).

Dans votre exemple, vous n'aurez pas de lecture fantôme, car vous ne sélectionnez qu'à partir d'une seule ligne (identifiée par la clé primaire). Vous pouvez avoir des lectures non répétables, donc si cela pose un problème, vous voudrez peut-être avoir un niveau d'isolement qui empêche cela. Dans Oracle, la transaction A peut également émettre un SELECT FOR UPDATE, puis la transaction B ne peut pas modifier la ligne tant que A n'est pas terminé.


6
Je ne comprends pas vraiment la logique d'une telle syntaxe ... Une lecture non répétable se produit lorsque la lecture est répétée (et une valeur différente obtenue) ??! ...
serhio

14
@serhio "non-répétable" fait référence au fait que vous pouvez lire une valeur une fois et obtenir x comme résultat, puis relire et obtenir y comme résultat, vous ne pouvez donc pas répéter (non répétable) les mêmes résultats à partir de deux requêtes distinctes de la même ligne, car cette valeur de ligne a été mise à jour entre les lectures.
BateTech

@Thilo Un exemple de cas d'utilisation réel où la lecture répétable peut créer des problèmes et où cela est nécessaire?
user104309

Que faire si le PK est modifié dans une autre transaction? Cela pourrait-il entraîner une lecture fantôme? (Une chose étrange à faire dans la plupart des cas, mais pas impossible.)
jpmc26

1
Les deux me
semblent identiques

127

Une façon simple que j'aime y penser est:

Les lectures non répétables et fantômes ont à voir avec les opérations de modification des données d'une transaction différente, qui ont été validées après le début de votre transaction, puis lues par votre transaction.

Les lectures non répétables se produisent lorsque votre transaction lit des MISES À JOUR validées à partir d'une autre transaction. La même ligne a maintenant des valeurs différentes de celles du début de votre transaction.

Les lectures fantômes sont similaires, mais lors de la lecture à partir d' INSERTS validés et / ou de DELETES à partir d'une autre transaction. De nouvelles lignes ou lignes ont disparu depuis le début de la transaction.

Les lectures incorrectes sont similaires aux lectures non répétables et fantômes, mais concernent la lecture de données NON ENGAGÉES et se produisent lorsqu'une mise à jour, une insertion ou une suppression d'une autre transaction est lue et que l'autre transaction n'a PAS encore validé les données. Il lit des données "en cours", qui peuvent ne pas être complètes et ne jamais être validées.


4
Cela a à voir avec les niveaux d'isolation des transactions et la concurrence. En utilisant le niveau d'isolation par défaut, vous n'obtiendrez pas de lectures modifiées et, dans la plupart des cas, vous souhaitez éviter les lectures modifiées. Il existe des niveaux d'isolement ou des conseils de requête qui autoriseront les lectures incorrectes, ce qui dans certains cas est un compromis acceptable pour obtenir une plus grande concurrence ou est nécessaire en raison d'un cas de pointe, comme le dépannage d'une transaction en cours à partir d'une autre connexion. Il est bon que l'idée d'une lecture sale ne passe pas le "test d'odeur" pour vous, car en règle générale, elles doivent être évitées, mais elles ont un but.
BateTech

1
@PHPAvenger est un cas d'utilisation pour le niveau d'isolement READ UNCOMMITTED: il y a toujours une possibilité de rencontrer un blocage entre une requête de sélection et une requête de mise à jour (expliqué ici ). Si la requête de sélection est trop complexe pour créer un index de couverture, afin d'éviter les blocages, vous voudrez utiliser un niveau d'isolement READ UNCOMMITED avec le risque de rencontrer des lectures sales, mais à quelle fréquence annulez-vous les transactions pour vous soucier de ces lectures sales non être permanent?!
petrica.martinescu

1
@ petrica.martinescu les problèmes causés par les lectures incorrectes ne concernent PAS seulement si une transaction est annulée ou non. Des lectures incorrectes peuvent renvoyer des résultats très inexacts en fonction de la manière dont les données des transactions en attente ont été modifiées. Imaginez une transaction qui effectue une série de plusieurs suppressions, mises à jour et / ou insertions. Si vous lisez les données au milieu de cette transaction à l'aide de "lecture non validée", elles sont incomplètes. Le niveau d'isolement des instantanés (dans SQL Server) est une bien meilleure alternative à la lecture non validée. Un cas d'utilisation valide pour lire le niveau d'isolement non validé dans un système de production est rare IMO.
BateTech

2
@DiponRoy excellente question. Le verrouillage implémenté si vous utilisez l'isolement de lecture répétable (RR) doit empêcher les suppressions de se produire sur les lignes qui ont été sélectionnées. J'ai vu différentes définitions des 2 niveaux iso au fil des ans, principalement en disant que fantôme est un changement dans la collection / # lignes retournées et RR est la même ligne modifiée. Je viens de vérifier que la documentation MS SQL mise à jour indique que les suppressions peuvent provoquer des suppressions non-RR ( docs.microsoft.com/en-us/sql/odbc/reference/develop-app/… ) donc je pense qu'il serait prudent de regrouper les suppressions dans la catégorie RR aussi
BateTech

2
@anir yes les insertions et les suppressions sont incluses dans les lectures modifiées. Exemple: démarrez une transaction, insérez 2 des 100 lignes de facture sur la connexion a, maintenant la connexion b lit ces 2 lignes avant que le trx ne soit validé et avant que les 98 autres lignes ne soient ajoutées, et n'inclut donc pas toutes les informations pour la facture. Ce serait une lecture sale impliquant un insert.
BateTech

28

Comme expliqué dans cet article , l' anomalie de lecture non répétable se présente comme suit:

entrez la description de l'image ici

  1. Alice et Bob démarrent deux transactions de base de données.
  2. Bob lit l'enregistrement de publication et la valeur de la colonne de titre est Transactions.
  3. Alice modifie le titre d'un enregistrement de publication donné à la valeur de ACID.
  4. Alice valide sa transaction de base de données.
  5. Si Bob relit l'enregistrement de publication, il observera une version différente de cette ligne de table.

Dans cet article sur Phantom Read , vous pouvez voir que cette anomalie peut se produire comme suit:

entrez la description de l'image ici

  1. Alice et Bob démarrent deux transactions de base de données.
  2. Bob lit tous les enregistrements post_comment associés à la ligne de publication avec la valeur d'identificateur 1.
  3. Alice ajoute un nouvel enregistrement post_comment qui est associé à la ligne de publication ayant la valeur d'identifiant 1.
  4. Alice valide sa transaction de base de données.
  5. Si Bob relit les enregistrements post_comment ayant la valeur de colonne post_id égale à 1, il observera une version différente de cet ensemble de résultats.

Ainsi, alors que la lecture non répétable s'applique à une seule ligne, la lecture fantôme concerne une plage d'enregistrements qui satisfont à un critère de filtrage de requête donné.


3
superbe visualisation @Vlad
dextermini

23

Lire les phénomènes

  • Lectures incorrectes : lire les données NON COMMISES d'une autre transaction
  • Lectures non répétables : lire les données COMMITTED à partir d'uneUPDATErequête d'une autre transaction
  • Lecture fantôme : lecture des données COMMITTED à partir d'unerequêteINSERTouDELETEd'une autre transaction

Remarque : les instructions DELETE d'une autre transaction ont également une très faible probabilité de provoquer des lectures non répétables dans certains cas. Cela se produit lorsque l'instruction DELETE, malheureusement, supprime la même ligne que votre transaction actuelle interrogeait. Mais c'est un cas rare, et beaucoup plus improbable dans une base de données contenant des millions de lignes dans chaque table. Les tables contenant des données de transaction ont généralement un volume de données élevé dans n'importe quel environnement de production.

Nous pouvons également observer que les MISES À JOUR peuvent être un travail plus fréquent dans la plupart des cas d'utilisation plutôt que de réelles INSERT ou DELETES (dans de tels cas, le danger de lectures non répétables reste seulement - les lectures fantômes ne sont pas possibles dans ces cas). C'est pourquoi UPDATES est traité différemment de INSERT-DELETE et l'anomalie résultante est également nommée différemment.

Il existe également un coût de traitement supplémentaire associé à la gestion des INSERT-DELETE, plutôt qu'à la gestion des MISES À JOUR.


Avantages des différents niveaux d'isolement

  • READ_UNCOMMITTED n'empêche rien. C'est le niveau d'isolement zéro
  • READ_COMMITTED n'en empêche qu'une seule, c'est-à-dire des lectures incorrectes
  • REPEATABLE_READ empêche deux anomalies: lectures incorrectes et lectures non répétables
  • SERIALIZABLE empêche les trois anomalies: lectures sales, lectures non répétables et lectures fantômes

Alors pourquoi ne pas simplement définir la transaction SERIALIZABLE à tout moment? Eh bien, la réponse à la question ci-dessus est: le paramètre SERIALIZABLE rend les transactions très lentes , ce que nous ne voulons pas non plus.

En fait, la consommation de temps de transaction est au taux suivant:

SERIALIZABLE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED

Le paramètre READ_UNCOMMITTED est donc le plus rapide .


Résumé

En fait, nous devons analyser le cas d'utilisation et décider d'un niveau d'isolement afin d'optimiser le temps de transaction et d'éviter la plupart des anomalies.

Notez que les bases de données par défaut ont le paramètre REPEATABLE_READ.


1
UPDATE ou DELETE peuvent avoir lieu pour les lectures non répétables ou il s'agit uniquement de UPDATE?
Dipon Roy

1
UPDATE ou DELETE peuvent avoir lieu pour les lectures non répétables
niket patel

En fait, nous pouvons résumer qu'en moyenne, une instruction DELETE aléatoire exécutée par une autre transaction sur la même base de données a une très faible probabilité de provoquer des lectures non répétables pour la transaction en cours. Mais la même instruction de suppression a 100% de chances de provoquer une lecture fantôme pour la transaction en cours. En regardant les choses de cette façon, mon écriture est un peu fausse si vous le prenez mot pour mot. Mais bon, je l'ai écrit intentionnellement de cette façon pour rendre les choses plus claires pour le lecteur.
Subhadeep Ray

+1 pour une explication simple et facile à comprendre. Cependant, je pense que la plupart des bases de données (oracle, mysql) ont un niveau d'isolement par défaut de Read Committed et que postgress utilise probablement par défaut repeatable_read
akila

7

Il existe une différence d'implémentation entre ces deux types de niveaux d'isolement.
Pour une "lecture non répétable", un verrouillage de ligne est nécessaire.
Pour la "lecture fantôme", un verrouillage de portée est nécessaire, même un verrouillage de table.
Nous pouvons implémenter ces deux niveaux en utilisant un protocole de verrouillage en deux phases .


Pour implémenter une lecture répétable ou sérialisable, il n'est pas nécessaire d'utiliser le verrouillage de ligne.
a_horse_with_no_name

5

Dans un système avec des lectures non répétables, le résultat de la deuxième requête de la transaction A reflétera la mise à jour de la transaction B - il verra le nouveau montant.

Dans un système qui autorise les lectures fantômes, si la transaction B devait insérer une nouvelle ligne avec ID = 1, la transaction A verra la nouvelle ligne lorsque la deuxième requête est exécutée; c'est-à-dire que les lectures fantômes sont un cas particulier de lecture non répétable.


Je ne pense pas que l'explication d'une lecture fantôme soit correcte. Vous pouvez obtenir des lectures fantômes même si les données sans validation ne sont jamais visibles. Voir l'exemple sur Wikipedia (lié dans les commentaires ci-dessus).
Thilo

1

La réponse acceptée indique surtout que la prétendue distinction entre les deux n’est en fait pas du tout significative.

Si "une ligne est récupérée deux fois et les valeurs à l'intérieur de la ligne diffèrent entre les lectures", alors ce ne sont pas la même ligne (pas le même tuple dans le bon discours RDB) et c'est alors en effet par définition aussi le cas que "la collection de les lignes renvoyées par la deuxième requête sont différentes de la première ".

Quant à la question "quel niveau d'isolement doit être utilisé", plus vos données sont d'une importance vitale pour quelqu'un, quelque part, plus il sera vrai que Serializable est votre seule option raisonnable.


0

Je pense qu'il y a une différence entre la lecture non répétable et la lecture fantôme.

Le non-répétable signifie qu'il y a des transactions de remorquage A et B. si B peut remarquer la modification de A, alors peut-être se produire une lecture sale, donc nous laissons B remarquer la modification de A après la validation de A.

Il y a un nouveau problème: nous laissons B remarquer la modification de A après la validation de A, cela signifie que A modifier une valeur de ligne que le B tient, parfois B relira la ligne, donc B obtiendra une nouvelle valeur différente avec la première fois que nous get, nous l'appelons Non répétable, pour résoudre le problème, nous laissons le B se souvenir de quelque chose (car je ne sais pas encore ce dont on se souviendra) quand B démarre.

Pensons à la nouvelle solution, nous pouvons remarquer qu'il y a également un nouveau problème, car nous laissons B se souvenir de quelque chose, donc quoi qu'il se soit passé dans A, le B ne peut pas être affecté, mais si B veut insérer des données dans la table et B Vérifiez le tableau pour vous assurer qu'il n'y a pas d'enregistrement, mais ces données ont été insérées par A, donc peut-être se produire une erreur. Nous l'appelons Phantom-read.


0

la lecture non répétable est un niveau d'isolement et la lecture fantôme (lecture de la valeur validée par d'autres transactions) est un concept (type de lecture, par exemple lecture sale ou lecture d'instantané). Le niveau d'isolement de lecture non répétable permet la lecture fantôme mais pas les lectures modifiées ou les lectures d'instantané.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.