Databasproffs konfronteras rutinmässigt med databasprestandaproblem som felaktig indexering och dåligt skriven kod i produktions-SQL-instanser. Anta att du uppdaterade en transaktion och SQL Server rapporterade följande dödlägesmeddelande. För DBA:er som precis har börjat kan detta komma som en chock.
I den här artikeln kommer vi att utforska SQL Server-låsningar och de bästa sätten att undvika dem.
Vad är ett dödläge för SQL Server?
SQL Server är en mycket transaktionsdatabas. Anta till exempel att du stödjer databasen för en online shoppingportal där du tar emot nya beställningar från kunder dygnet runt. Flera användare utför sannolikt samma aktivitet samtidigt. I det här fallet bör din databas följa egenskaperna Atomicity, Consistency, Isolation, Durability (ACID) för att vara konsekvent, pålitlig och skydda dataintegriteten.
Bilden nedan beskriver ACID-egenskaperna i en relationsdatabas.
För att följa ACID-egenskaperna använder SQL Server låsmekanismer, begränsningar och förutskrivningsloggning. Olika låstyper inkluderar:exklusivt lås(X), delat lås(S), uppdateringslås (U), avsiktslås (I), schemalås (SCH) och bulkuppdateringslås (BU). Dessa lås kan erhållas på nyckel-, tabell-, rad-, sida- och databasnivå.
Anta att du har två användare, John och Peter som är anslutna till kunddatabasen.
- John vill uppdatera posterna för kunden som har [customerid] 1.
- Samtidigt vill Peter hämta värdet för kunden som har [kundnummer] 1.
I det här fallet använder SQL Server följande lås för både John och Peter.
Lås för John
- Det krävs ett lås med intent exklusivt (IX) på kundtabellen och sidan som innehåller posten.
- Det krävs ytterligare ett exklusivt (X) lås på raden som John vill uppdatera. Det hindrar någon annan användare från att ändra raddata tills process A släpper låset.
Lås för Peter
- Den får ett avsiktsdelat lås (IS) på kundtabellen och sidan som innehåller posten enligt where-klausulen.
- Den försöker ta ett delat lås för att läsa raden. Den här raden har redan ett exklusivt lås för John.
I det här fallet måste Peter vänta tills John är klar med sitt arbete och släpper det exklusiva låset. Denna situation kallas blockering.
Anta nu att John och Peter i ett annat scenario har följande lås.
- John har ett exklusivt lås på kundbordet för kund-id 1.
- Peter har ett exklusivt lås på beställningsbordet för kund-id 1.
- John kräver ett exklusivt lås på orderbordet för att slutföra sin transaktion. Peter har redan ett exklusivt lås på beställningsbordet.
- Peter kräver ett exklusivt lås på kundbordet för att slutföra sin transaktion. John har redan ett exklusivt lås på kundbordet.
I det här fallet kan ingen av transaktionerna fortsätta eftersom varje transaktion kräver en resurs som innehas av den andra transaktionen. Denna situation är känd som ett dödläge för SQL Server.
SQL Server-dödlägesövervakningsmekanismer
SQL Server övervakar dödlägessituationer med jämna mellanrum med hjälp av tråden för dödlägesövervakning. Detta kontrollerar processerna som är involverade i ett dödläge och identifierar om en session har blivit ett dödlägesoffer. Den använder en intern mekanism för att identifiera dödlägesofferprocessen. Som standard anses transaktionen med minsta mängd resurser som krävs för återställning som ett offer.
SQL Server dödar offersessionen så att en annan session kan skaffa det nödvändiga låset för att slutföra sin transaktion. Som standard kontrollerar SQL Server dödläget var 5:e sekund med hjälp av dödlägesmonitorn. Om den upptäcker ett dödläge kan det minska frekvensen från 5 sekunder till 100 millisekunder beroende på dödläget. Den återställer övervakningstråden till 5 sekunder om frekventa dödlägen inte inträffar.
När SQL Server dödar en process som ett dödlägesoffer får du följande meddelande. I den här sessionen var process ID 69 ett dödlägesoffer.
Konsekvenserna av att använda SQL Server-deadlock-prioritetssatser
Som standard markerar SQL Server transaktionen med den billigaste återställningen som ett dödlägesoffer. Användare kan ställa in dödlägesprioritet i en transaktion med DEADLOCK_PRIORITY-satsen.
SET DEADLOCK_PRIORITY
Den använder följande argument:
- Låg:Det motsvarar dödlägesprioritet -5
- Normal:Det är standardprioriteten för dödläge 0
- Hög:Det är den högsta dödlägets prioritet 5.
Vi kan också ställa in numeriska värden för dödlägesprioriteten från -10 till 10 (totalt 21 värden).
Låt oss titta på några exempel på prioriterade uttalanden om dödläge.
Exempel 1:
Session 1 med dödlägesprioritet:Normal (0)> Session 2 med dödlägesprioritet:Låg (-5)
Dödlägesoffer: Session 2
Exempel 2:
Session 1 med dödlägesprioritet:Normal (0)
Dödlägesoffer: Session 1
Exempel 3
Session 1 med dödlägesprioritet:-3> Session 2 med dödlägesprioritet:-7
Exempel 4:
Session 1 med dödlägesprioritet:-5
Dödlägesoffer: Session 1
En dödlägesgraf är en visuell representation av dödlägesprocesserna, deras låsningar och dödlägesoffret. Vi kan aktivera spårningsflaggorna 1204 och 1222 för att fånga deadlock-detaljinformation i ett XML- och grafiskt format. Vi kan använda den utökade standardhändelsen system_health för att få information om dödläget. Ett snabbt och enkelt sätt att tolka dödläget är genom en dödlägesgraf. Låt oss simulera ett dödläge och se dess motsvarande dödlägesdiagram.
För den här demonstrationen skapade vi tabellen Kunder och beställningar och infogade några exempelposter.
Sedan öppnade vi ett nytt frågefönster och aktiverade spårningsflaggan globalt.
DBCC traceon(1222,-1)
När vi aktiverade spårningsflaggan för dödläge startade vi två sessioner och körde frågan i följande ordning:
I det här exemplet väljer SQL Server ett dödlägesoffer (sessions-ID 65) och dödar transaktionen. Låt oss hämta dödlägesdiagrammet från den utökade händelsesessionen system_health.
Den här frågan ger oss en deadlock XML som kräver en erfaren DBA för att tolka informationen.
Vi sparar denna dödläges-XML med tillägget .XDL och när vi öppnar XDL-filen i SSMS får vi dödlägesdiagrammet som visas nedan.
Denna dödlägesgraf ger följande information:
Den representerar ett dödlägesoffer genom att stryka över ovalen i dödlägesdiagrammet.
Du kan fånga information om dödläge för SQL Server på följande sätt:
1) dödläge för bokmärkessökning
Bokmärkessökning är ett vanligt dödläge i SQL Server. Det uppstår på grund av en konflikt mellan select-satsen och DML-satserna (insert, update and delete). Vanligtvis väljer SQL Server select-satsen som ett dödlägesoffer eftersom det inte orsakar dataförändringar och återställningen går snabbt. För att undvika bokmärkessökningen kan du använda ett täckande index. Du kan också använda en NOLOCK-frågetips i select-satserna, men den läser oengagerad data.
2) Deadlock för räckviddsskanning
Ibland använder vi en SERIALISERBAR isoleringsnivå på servernivå eller sessionsnivå. Det är en restriktiv isoleringsnivå för samtidighetskontroll och kan skapa räckviddsskanningslås istället för sid- eller radnivålås. I isoleringsnivån SERIALIZABLE kan användare inte läsa data om den är modifierad men väntar på att bli committerad i en transaktion. På liknande sätt, om en transaktion läser data, kan en annan transaktion inte ändra den. Det ger den lägsta samtidigheten så vi bör använda denna isoleringsnivå i specifika applikationskrav.
3) Cascading constraint deadlock
SQL Server använder förälder-barn-relationen mellan tabeller med hjälp av begränsningarna för främmande nyckel. I det här scenariot, om vi uppdaterar eller tar bort en post från den överordnade tabellen, krävs det nödvändiga låsningar på den underordnade tabellen för att förhindra föräldralösa poster. För att eliminera dessa låsningar bör du alltid modifiera data i en underordnad tabell först följt av överordnade data. Du kan också arbeta direkt med den överordnade tabellen med alternativen DELETE CASCADE eller UPPDATERA CASCADE. Du bör också skapa lämpliga index på kolumnerna för främmande nyckel.
4) Intra-query parallellism dödläge
När en användare skickar en fråga till SQL-frågemotorn skapar frågeoptimeraren en optimerad exekveringsplan. Den kan köra frågan i seriell eller parallell ordning beroende på frågekostnaden, den maximala graden av parallellitet (MAXDOP) och kostnadströskeln för parallellitet.
I ett parallellitetsläge tilldelar SQL Server flera trådar. Ibland för en stor fråga i ett parallellitetsläge börjar dessa trådar blockera varandra. Så småningom förvandlas det till dödlägen. I det här fallet måste du granska exekveringsplanen och din MAXDOP och kostnadströskel för parallellitetskonfigurationer. Du kan också ange MAXDOP på sessionsnivå för att felsöka dödläget.
5) Deadlock i omvänd objektordning
I denna typ av dödläge får flera transaktioner tillgång till objekt i en annan ordning i T-SQL. Detta orsakar blockering bland resurserna för varje session och omvandlar det till ett dödläge. Du vill alltid komma åt objekt i en logisk ordning så att det inte leder till ett dödläge.
Deadlocks är en naturlig mekanism i SQL Server för att undvika att sessionen håller lås och väntar på andra resurser. Du bör fånga dödlägesfrågor och optimera dem så att de inte kommer i konflikt med varandra. Det är viktigt att fånga låset under en kort tidsperiod och släppa det, så att andra frågor effektivt kan använda det.
SQL Server-låsningar inträffar, och medan SQL Server internt hanterar låsta situationer, bör du försöka minimera dem när det är möjligt. Några av de bästa sätten att eliminera dödlägen är genom att skapa ett index, tillämpa programkodändringar eller noggrant inspektera resurserna i ett dödlägesdiagram. För fler tips om hur du undviker SQL-deadlocks, kolla in vårt inlägg: Avoiding SQL-deadlocks with query tuning.SQL Server dödlägen med hjälp av dödlägesdiagram
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 av dödlägen i SQL Server
Användbara sätt att undvika och minimera låsningar i SQL Server
SQL Server-dödlägesöverväganden