sql >> Database teknologi >  >> RDS >> Database

Det gentagelige læseisolationsniveau

[ Se indekset for hele serien ]

Den serialiserbare isolationsniveau giver fuldstændig beskyttelse fra samtidighedseffekter, der kan true dataintegriteten og føre til forkerte forespørgselsresultater. Brug af serialiserbar isolation betyder, at hvis en transaktion, der kan påvises at give korrekte resultater uden samtidig aktivitet, vil den fortsætte med at fungere korrekt, når den konkurrerer med enhver kombination af samtidige transaktioner.

Dette er en meget stærk garanti , og en, der sandsynligvis matcher de intuitive forventninger til transaktionsisolering hos mange T-SQL-programmører (selvom i sandhed, relativt få af disse rutinemæssigt vil bruge serialiserbar isolation i produktionen).

SQL-standarden definerer tre yderligere isolationsniveauer, der tilbyder langt svagere ACID isolationsgarantier end kan serialiseres til gengæld for potentielt højere samtidighed og færre potentielle bivirkninger som blokering, deadlocking og afbrydelser i forbindelse med commit-time.

I modsætning til serialiserbar isolation er de andre isolationsniveauer udelukkende defineret i form af visse samtidighedsfænomener, der kan observeres. Det næststærkeste af standard isolationsniveauerne efter serialiserbar er navngivet repeatable read . SQL-standarden specificerer, at transaktioner på dette niveau tillader et enkelt samtidighedsfænomen kendt som et fantom .

Ligesom vi tidligere har set vigtige forskelle mellem den almindelige intuitive betydning af ACID-transaktionsegenskaber og virkeligheden, omfatter fantomfænomenet en bredere vifte af adfærd, end man ofte forstår.

Dette indlæg i serien ser på de faktiske garantier, som den gentagelige læsning giver isolationsniveau, og viser nogle af de fantomrelaterede adfærd, der kan stødes på. For at illustrere nogle punkter vil vi henvise til følgende simple eksempelforespørgsel, hvor den simple opgave er at tælle det samlede antal rækker i en tabel:

SELECT COUNT_BIG(*)
FROM dbo.SomeTable;

Gentagelig læsning

En mærkelig ting ved det gentagelige læseisolationsniveau er, at det ikke gør det faktisk garantere, at læsninger er gentagelige , i det mindste i én almindeligt forstået betydning. Dette er endnu et eksempel, hvor intuitiv betydning alene kan være vildledende. At udføre den samme forespørgsel to gange inden for den samme gentagelige læsetransaktion kan faktisk returnere forskellige resultater.

Derudover betyder SQL Server-implementeringen af ​​gentagelig læsning, at en enkelt læsning af et sæt data kan gå glip af nogle rækker der logisk set burde overvejes i forespørgselsresultatet. Selvom denne adfærd unægteligt er implementeringsspecifik, er den helt i tråd med definitionen af ​​gentagelig læsning i SQL-standarden.

Den sidste ting, jeg hurtigt vil bemærke, før jeg dykker ned i detaljer, er, at gentagelig læsning i SQL Server ikke give et punkt-i-tidsbillede af dataene.

Ikke-gentagelige læsninger

Det gentagelige læseisolationsniveau giver en garanti for, at data ikke ændres i hele transaktionens levetid når den er blevet læst for første gang.

Der er et par finesser indeholdt i denne definition. For det første tillader det at data ændres efter transaktionen starter, men før dataene er første tilgås. For det andet er der ingen garanti for, at transaktionen faktisk vil støde på alle de data, der logisk kvalificerer. Vi vil snart se eksempler på begge disse.

Der er en anden foreløbig, vi skal have for at komme af vejen hurtigt, som har at gøre med den eksempelforespørgsel, vi vil bruge. Retfærdigvis er semantikken i denne forespørgsel lidt uklar. Med fare for at lyde lidt filosofisk, hvad betyder det så betyder at tælle antallet af rækker i tabellen? Skal resultatet afspejle tabellens tilstand, som den var på et bestemt tidspunkt? Skal dette tidspunkt være starten eller slutningen af ​​transaktionen, eller noget andet?

Dette kan virke lidt kræsent, men spørgsmålet er gyldigt i enhver database, der understøtter samtidige datalæsninger og ændringer. Det kan tage vilkårligt lang tid at udføre vores eksempelforespørgsel (f.eks. givet en tilstrækkelig stor tabel eller ressourcebegrænsninger), så samtidige ændringer er ikke kun mulige, de kan være uundgåelige .

Det grundlæggende problem her er potentialet for samtidighedsfænomenet, der omtales som et fantom i SQL-standarden. Mens vi tæller rækker i tabellen, kan en anden samtidig transaktion indsætte nye rækker et sted, vi allerede har tjekket, eller ændre en række vi ikke har tjekket endnu på en sådan måde at den flytter til et sted vi allerede har kigget. Folk tænker ofte på fantomer som rækker, der på magisk vis kan dukke op, når de læses for anden gang, i en separat erklæring, men virkningerne kan være meget mere subtile end som så.

Eksempel på samtidig indsættelse

Dette første eksempel viser, hvordan samtidige indsættelser kan producere en ikke-gentagelig læse og/eller resultere i, at rækker springes over. Forestil dig, at vores testtabel oprindeligt indeholder fem rækker med værdierne vist nedenfor:

Vi indstiller nu isolationsniveauet til gentagelig læsning, starter en transaktion og kører vores tælleforespørgsel. Som du ville forvente, er resultatet fem . Intet stort mysterium indtil videre.

Eksekverer stadig i den samme gentagelige læste transaktion , kører vi tælleforespørgslen igen, men denne gang mens en anden samtidig transaktion indsætter nye rækker i den samme tabel. Diagrammet nedenfor viser rækkefølgen af ​​hændelser, hvor den anden transaktion tilføjer rækker med værdierne 2 og 6 (du har måske bemærket, at disse værdier var iøjnefaldende ved deres fravær lige over):

Hvis vores tælleforespørgsel kørte på serialiserbar isolationsniveau, ville det med garanti tælle enten fem eller syv rækker (se den forrige artikel i denne serie, hvis du har brug for en genopfriskning af, hvorfor det er tilfældet). Hvordan fungerer det at løbe på mindre isolerede gentageligt læseniveau påvirker tingene?

Nå, gentagelig læsning isolation garanterer, at den anden kørsel af tælleforespørgslen vil se alle de tidligere læste rækker, og de vil være i samme tilstand som før. Fangsten er, at gentagelig læseisolering siger ingenting om, hvordan transaktionen skal behandle de nye rækker (fantomerne).

Forestil dig, at vores rækketællingstransaktion (T1 ) har en fysisk udførelsesstrategi, hvor rækker søges i en stigende indeksrækkefølge. Dette er et almindeligt tilfælde, for eksempel når en fremadrettet b-tree indeksscanning anvendes af udførelsesmotoren. Nu, lige efter transaktion T1 tæller række 1 og 3 i stigende rækkefølge, transaktion T2 kan snige sig ind, indsætte nye rækker 2 og 6 og derefter begå sin transaktion.

Selvom vi primært tænker på logisk adfærd på dette tidspunkt, skal jeg nævne, at der ikke er noget i SQL Server-låseimplementeringen af ​​gentagelig læsning for at forhindre transaktion T2 fra at gøre dette. Delte låse taget af transaktion T1 på tidligere læste rækker forhindrer disse rækker i at blive ændret, men de forhindrer ikke nye rækker fra at blive indsat i rækken af ​​værdier testet af vores tælleforespørgsel (i modsætning til nøgleområdelåsene i låsning, der kan serialiseres isolation).

Uanset hvad, med de to nye rækker begået, transaktion T1 fortsætter sin søgning i stigende rækkefølge og støder til sidst på række 4, 5, 6 og 7. Bemærk, at T1 ser ny række 6 i dette scenarie, men ikke ny række 2 (på grund af den bestilte søgning og dens position, da indsættelsen fandt sted).

Resultatet er, at den gentagelige læsning tælleforespørgsel rapporterer, at tabellen indeholder seks rækker (værdier 1, 3, 4, 5, 6 og 7). Dette resultat er ikke i overensstemmelse med det tidligere resultat af fem rækker opnået inden for samme transaktion . Den anden læsning talte fantomrække 6, men missede fantomrække 2. Så meget for den intuitive betydning af en gentagelig læsning!

Eksempel på samtidig opdatering

En lignende situation kan opstå med en samtidig opdatering i stedet for en indsats. Forestil dig, at vores testtabel er nulstillet til at indeholde de samme fem rækker som før:

Denne gang kører vi kun vores optællingsforespørgsel én gang ved den gentagelige læsning isolationsniveau, mens en anden samtidig transaktion opdaterer rækken med værdi 5 til at have en værdi på 2:

Transaktion T1 begynder igen at tælle rækker, (i stigende rækkefølge) støder først på række 1 og 3. Nu glider transaktion T2 ind, ændrer værdien af ​​række 5 til 2 og forpligter:

Jeg har vist den opdaterede række i samme position som før for at gøre ændringen tydelig, men b-tree-indekset, vi scanner, bevarer dataene i logisk rækkefølge, så det virkelige billede er tættere på dette:

Pointen er, at transaktion T1 scanner samtidig den samme struktur i fremadgående rækkefølge, idet den i øjeblikket er placeret lige efter indtastningen for værdi 3. Tælleforespørgslen fortsætter med at scanne fremad fra det tidspunkt og finder række 4 og 7 (men selvfølgelig ikke række 5).

For at opsummere, så tælleforespørgslen række 1, 3, 4 og 7 i dette scenarie. Den rapporterer en optælling på fire rækker – hvilket er mærkeligt, for tabellen ser ud til at have indeholdt fem rækker hele vejen igennem!

En anden kørsel af tælleforespørgslen inden for den samme gentagelige læsetransaktion ville rapportere fem rækker af lignende årsager som før. Som en sidste bemærkning, hvis du undrer dig, giver samtidige sletninger ikke mulighed for en fantombaseret anomali under gentagelig læseisolering.

Sidste tanker

De foregående eksempler brugte begge scanninger i stigende rækkefølge af en indeksstruktur til at præsentere et simpelt overblik over den slags effekter, fantomer kan have på en gentagelig læsning forespørgsel. Det er vigtigt at forstå, at disse illustrationer ikke på nogen vigtig måde er afhængige af scanningsretningen eller det faktum, at der blev brugt et b-træ-indeks. Gør venligst ikke danne den opfattelse, at bestilte scanninger på en eller anden måde er ansvarlige og derfor skal undgås!

De samme samtidighedseffekter kan ses med en faldende scanning af en indeksstruktur eller i en række andre fysiske dataadgangsscenarier. Den overordnede pointe er, at fantomfænomener er specifikt tilladt (men ikke påkrævet) af SQL-standarden for transaktioner på det gentagelige læseniveau af isolation.

Ikke alle transaktioner kræver den komplette isolationsgaranti, der leveres af serialiserbar isolation, og ikke mange systemer kunne tolerere bivirkningerne, hvis de gjorde det. Ikke desto mindre kan det betale sig at have en god forståelse af, præcis hvilke garantier de forskellige isolationsniveauer giver.

Næste gang

Den næste del i denne serie ser på de endnu svagere isolationsgarantier, der tilbydes af SQL Servers standard isolationsniveau, læs committed .

[ Se indekset for hele serien ]


  1. PDO MySQL:Brug PDO::ATTR_EMULATE_PREPARES eller ej?

  2. At iterere et ResultSet ved hjælp af JDBC for Oracle tager meget tid omkring 16s?

  3. Hentning af returværdien fra JDBC MSSQL

  4. Konverter latin1-tegn på en UTF8-tabel til UTF8