sql >> Databasteknik >  >> RDS >> Sqlserver

SQL Server-låsets anatomi och de bästa sätten att undvika dem

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

SQL Server dödlägen med hjälp av dödlägesdiagram

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.

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

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:

  • Den första sessionen startar en transaktion för att uppdatera kundtabellen för kund-ID 1.
  • Den andra sessionen startar en transaktion för att uppdatera ordertabellen för order-ID 10.
  • Den första sessionen försöker uppdatera ordertabellen för samma order-ID 10. Den andra sessionen låser redan den här raden. Session 1 är blockerad på grund av låsningarna som innehas av session 2.
  • Nu, för session 2, vill vi uppdatera kundtabellen för kund-ID 1. Det genererar en dödlägessituation där både session ID 63 och ID 65 inte kan fortsätta.

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.

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;

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:

  • Processnoder:  I ovalen får du processrelaterad information.
  • Resursnoder:  Resursnoder (fyrkantig ruta) ger information om de objekt som är involverade i transaktionerna tillsammans med låsen. I det här exemplet visar den RID-lås eftersom vi inte har några index för båda tabellerna.
  • Kanter:  En kant förbinder processnoden och resursnoden. Den visar resursägaren och begär låsläge.

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:

  • SQL Server-profilerare
  • Utökade SQL Server-händelser
  • SQL Server-felloggar
  • Standardspår i SQL Server

5 typer av dödlägen i SQL Server

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.

Användbara sätt att undvika och minimera låsningar i SQL Server

  • Försök att hålla transaktioner korta; detta kommer att undvika att låsa en transaktion under en lång tidsperiod.
  • Åtkomst till objekt på ett liknande logiskt sätt i flera transaktioner.
  • Skapa ett täckande index för att minska risken för ett dödläge.
  • Skapa index som matchar kolumnerna för främmande nyckel. På så sätt kan du eliminera dödlägen på grund av överlappande referensintegritet.
  • Ställ in dödlägesprioriteter med sessionsvariabeln SET DEADLOCK_PRIORITY. Om du ställer in dödlägesprioritet dödar SQL Server sessionen med lägst dödlägesprioritet.
  • Använd felhanteringen med hjälp av try-catch-blocken. Du kan fånga dödlägesfelet och köra transaktionen igen i händelse av ett dödlägesoffer.
  • Ändra isoleringsnivån till READ COMMITTED SNAPSHOT ISOLATION eller SNAPSHOT ISOLATION. Detta ändrar SQL Server-låsningsmekanismen. Du bör dock vara försiktig med att ändra isoleringsnivån, eftersom det kan påverka andra frågor negativt.

SQL Server-dödlägesöverväganden

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.


  1. Förstå effekterna av hög latens i High Availability MySQL- och MariaDB-lösningar

  2. Blir de snabbare om du lägger till 'LIMIT 1' i MySQL-frågor när du vet att det bara kommer att bli ett resultat?

  3. Hur man ställer in asynkron replikering mellan MariaDB Galera-kluster

  4. Återställ PostgreSQL primärnyckel till 1