Databaseprofessionelle bliver rutinemæssigt konfronteret med problemer med databaseydeevne som ukorrekt indeksering og dårligt skrevet kode i produktions-SQL-forekomster. Antag, at du opdaterede en transaktion, og SQL Server rapporterede følgende deadlock-meddelelse. For DBA'er, der lige er startet, kan dette komme som et chok.
I denne artikel vil vi udforske SQL Server-deadlocks og de bedste måder at undgå dem på.
Hvad er en SQL Server-deadlock?
SQL Server er en meget transaktionsbaseret database. Antag for eksempel, at du understøtter databasen til en online shoppingportal, hvor du modtager nye ordrer fra kunder døgnet rundt. Flere brugere udfører sandsynligvis den samme aktivitet på samme tid. I dette tilfælde skal din database følge egenskaberne Atomicity, Consistency, Isolation, Durability (ACID) for at være konsistent, pålidelig og beskytte dataintegriteten.
Billedet nedenfor beskriver ACID-egenskaberne i en relationsdatabase.
For at følge ACID-egenskaberne bruger SQL Server låsemekanismer, begrænsninger og fremskrivningslogning. Forskellige låsetyper omfatter:eksklusiv lås(X), delt lås(S), opdateringslås (U), hensigtslås (I), skemalås (SCH) og masseopdateringslås (BU). Disse låse kan erhverves på nøgle-, tabel-, række-, side- og databaseniveau.
Antag, at du har to brugere, John og Peter, som er forbundet til kundedatabasen.
- John ønsker at opdatere registreringerne for den kunde, der har [customerid] 1.
- Peter ønsker samtidig at hente værdien for kunden, der har [kunde-id] 1.
I dette tilfælde bruger SQL Server følgende låse til både John og Peter.
Låse til John
- Det kræver en hensigtseksklusiv (IX) lås på kundetabellen og siden, der indeholder posten.
- Det kræver yderligere en eksklusiv (X) lås på rækken, som John vil opdatere. Det forhindrer enhver anden bruger i at ændre rækkedataene, indtil proces A frigiver sin lås.
Låse til Peter
- Den får en hensigtsdelt (IS) lås på kundetabellen og siden, der indeholder posten i henhold til where-klausulen.
- Den forsøger at tage en delt lås for at læse rækken. Denne række har allerede en eksklusiv lås til John.
I dette tilfælde skal Peter vente, indtil John er færdig med sit arbejde og frigiver den eksklusive lås. Denne situation er kendt som blokering.
Antag nu, at John og Peter i et andet scenarie har følgende låse.
- John har en eksklusiv lås på kundebordet til kunde-id 1.
- Peter har en eksklusiv lås på ordretabellen for kunde-id 1.
- John kræver en eksklusiv lås på ordrebordet for at afslutte sin transaktion. Peter har allerede en eksklusiv lås på ordrebordet.
- Peter kræver en eksklusiv lås på kundebordet for at afslutte sin transaktion. John har allerede en eksklusiv lås på kundebordet.
I dette tilfælde kan ingen af transaktionerne fortsætte, fordi hver transaktion kræver en ressource, som den anden transaktion besidder. Denne situation er kendt som en SQL Server-deadlock.
SQL Server dødvandsovervågningsmekanismer
SQL Server overvåger deadlock situationer med jævne mellemrum ved hjælp af deadlock monitor tråden. Dette tjekker processerne involveret i en dødvande og identificerer, om en session er blevet et dødvande offer. Den bruger en intern mekanisme til at identificere dødvande-offerprocessen. Som standard betragtes transaktionen med den mindste mængde ressourcer, der kræves til tilbagerulning, som et offer.
SQL Server dræber offersessionen, så en anden session kan erhverve den nødvendige lås for at fuldføre sin transaktion. Som standard kontrollerer SQL Server deadlock-situationen hvert 5. sekund ved hjælp af deadlock-monitoren. Hvis den registrerer en dødlås, kan den reducere frekvensen fra 5 sekunder til 100 millisekunder afhængigt af dødvandet. Den nulstiller igen overvågningstråden til 5 sekunder, hvis der ikke opstår hyppige deadlocks.
Når SQL Serveren dræber en proces som dødvande offer, vil du modtage følgende besked. I denne session var proces ID 69 et dødvande offer.
Konsekvenserne af at bruge SQL Server-deadlock-prioritetssætninger
Som standard markerer SQL Server transaktionen med den billigste rollback som et dødvande-offer. Brugere kan indstille deadlock-prioriteten i en transaktion ved hjælp af DEADLOCK_PRIORITY-sætningen.
SET DEADLOCK_PRIORITY
Den bruger følgende argumenter:
- Lav:Det svarer til deadlock-prioritet -5
- Normal:Det er standard deadlock-prioritet 0
- Høj:Det er den højeste deadlock-prioritet 5.
Vi kan også indstille numeriske værdier for deadlock-prioriteten fra -10 til 10 (i alt 21 værdier).
Lad os se på et par eksempler på deadlock-prioritetserklæringer.
Eksempel 1:
Session 1 med deadlock-prioritet:Normal (0)> Session 2 med deadlock-prioritet:Lav (-5)
Deadlock Victim: Session 2
Eksempel 2:
Session 1 med deadlock-prioritet:Normal (0)
Deadlock Victim: Session 1
Eksempel 3
Session 1 med deadlock-prioritet:-3> Session 2 med deadlock-prioritet:-7
Eksempel 4:
Session 1 med deadlock-prioritet:-5
Deadlock Victim: Session 1
En dødvandsgraf er en visuel repræsentation af dødvandeprocesserne, deres låse og dødsfaldsofferet. Vi kan aktivere sporingsflag 1204 og 1222 til at fange deadlock detaljerede oplysninger i et XML og grafisk format. Vi kan bruge den udvidede standard system_health-begivenhed til at indhente deadlock-oplysningerne. En hurtig og nem måde at fortolke dødvandet på er gennem en dødvandsgraf. Lad os simulere en deadlock-tilstand og se dens tilsvarende dødlock-graf.
Til denne demonstration oprettede vi kunde- og ordretabellen og indsatte et par eksempelposter.
Derefter åbnede vi et nyt forespørgselsvindue og aktiverede sporingsflaget globalt.
DBCC traceon(1222,-1)
Da vi aktiverede dødvandssporingsflaget, startede vi to sessioner og udførte forespørgslen i nedenstående rækkefølge:
I dette eksempel vælger SQL Server et dødvande-offer (sessions-id 65) og dræber transaktionen. Lad os hente deadlock-grafen fra den udvidede system_health-hændelsessession.
Denne forespørgsel giver os en deadlock XML, som kræver en erfaren DBA for at fortolke oplysningerne.
Vi gemmer denne deadlock XML ved hjælp af .XDL-udvidelsen, og når vi åbner XDL-filen i SSMS, får vi deadlock-grafen vist nedenfor.
Denne deadlock-graf giver følgende information:
Det repræsenterer et dødvande-offer ved at strege ovalen over i dødvandsgrafen.
Du kan fange SQL Server-deadlock-oplysninger på følgende måder:
1) Deadlock til bogmærkeopslag
Bogmærkeopslag er en almindeligt forekommende dødvande i SQL Server. Det opstår på grund af en konflikt mellem select-sætningen og DML-sætningerne (insert, update and delete). Normalt vælger SQL Server select-sætningen som et dødvande-offer, fordi det ikke forårsager dataændringer, og tilbagerulningen er hurtig. For at undgå bogmærkeopslag kan du bruge et dækkende indeks. Du kan også bruge et NOLOCK-forespørgselstip i select-sætningerne, men det læser ikke-forpligtede data.
2) Deadlock for rækkeviddescanning
Nogle gange bruger vi et SERIALIZABLE isolationsniveau på serverniveau eller sessionsniveau. Det er et restriktivt isolationsniveau for samtidighedskontrol og kan oprette rækkescanningslåse i stedet for låse på side- eller rækkeniveau. I isolationsniveauet SERIALIZABLE kan brugere ikke læse data, hvis de er ændret, men venter på at blive forpligtet i en transaktion. På samme måde, hvis en transaktion læser data, kan en anden transaktion ikke ændre dem. Det giver den laveste samtidighed, så vi bør bruge dette isolationsniveau i specifikke applikationskrav.
3) Cascading constraint deadlock
SQL Server bruger forældre-barn-relationen mellem tabeller ved hjælp af fremmednøgle-begrænsningerne. I dette scenarie, hvis vi opdaterer eller sletter en post fra den overordnede tabel, kræver det nødvendige låse på den underordnede tabel for at forhindre forældreløse poster. For at eliminere disse deadlocks bør du altid ændre data i en undertabel først efterfulgt af de overordnede data. Du kan også arbejde direkte med den overordnede tabel ved at bruge indstillingerne SLET CASCADE eller OPDATERE CASCADE. Du bør også oprette passende indekser på kolonnerne med fremmednøgle.
4) Intra-query parallelisme dødvande
Når en bruger sender en forespørgsel til SQL-forespørgselsmotoren, opbygger forespørgselsoptimering en optimeret eksekveringsplan. Den kan udføre forespørgslen i en seriel eller parallel rækkefølge afhængigt af forespørgselsomkostningerne, den maksimale grad af parallelitet (MAXDOP) og omkostningstærsklen for parallelitet.
I en parallelitetstilstand tildeler SQL Server flere tråde. Nogle gange for en stor forespørgsel i paralleltilstand begynder disse tråde at blokere hinanden. Til sidst konverteres det til dødvande. I dette tilfælde skal du gennemgå eksekveringsplanen og din MAXDOP og omkostningstærskel for parallelitetskonfigurationer. Du kan også angive MAXDOP på sessionsniveau for at fejlfinde scenariet med dødvande.
5) Omvendt objektrækkefølge deadlock
I denne type dødvande får flere transaktioner adgang til objekter i en anden rækkefølge i T-SQL. Dette forårsager blokering blandt ressourcerne for hver session og konverterer det til et dødvande. Du vil altid have adgang til objekter i en logisk rækkefølge, så det ikke fører til en dødvande situation.
Deadlocks er en naturlig mekanisme i SQL Server til at undgå, at sessionen holder låse og venter på andre ressourcer. Du bør fange deadlock-forespørgsler og optimere dem, så de ikke kommer i konflikt med hinanden. Det er vigtigt at fange låsen i et kort tidsrum og frigive den, så andre forespørgsler effektivt kan bruge den.
SQL Server-deadlocks opstår, og mens SQL Server internt håndterer deadlock-situationer, bør du prøve at minimere dem, når det er muligt. Nogle af de bedste måder at fjerne dødvande på er ved at oprette et indeks, anvende applikationskodeændringer eller omhyggeligt at inspicere ressourcerne i en dødvandegraf. For flere tips til, hvordan du undgår SQL-deadlocks, kan du se vores indlæg: Avoiding SQL-deadlocks with query tuning.SQL Server-deadlocks ved hjælp af deadlock-grafer
CREATE TABLE Customer
(ID INT IDENTITY(1,1), CustomerName VARCHAR(20))
GO
CREATE TABLE Orders
(OrderID INT IDENTITY(1,1), ProductName VARCHAR(50))
GO
INSERT INTO Customer(CustomerName) VALUES ('Rajendra')
Go 100
S INSERT INTO Orders(ProductName) VALUES ('Laptop')
Go 100
SELECT XEvent.query('(event/data/value/deadlock)[1]') AS DeadlockGraph
FROM (
SELECT XEvent.query('.') AS XEvent
FROM (
SELECT CAST(target_data AS XML) AS TargetData
FROM sys.dm_xe_session_targets st
INNER JOIN sys.dm_xe_sessions s
ON s.address = st.event_session_address
WHERE s.NAME = ‘system_health’
AND st.target_name = ‘ring_buffer’
) AS Data
CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]
') AS XEventData(XEvent)
) AS source;
5 typer dødvande i SQL Server
Nyttige måder at undgå og minimere SQL Server-deadlocks
SQL Server-deadlock-overvejelser