Introduktion
Relationsdatabaser följer ACID-egenskaperna i hur de implementerar transaktioner – Atomicity, Consistency, Isolation och Durability. Isolering är nödvändigt för att säkerställa att flera transaktioner inte kan orsaka ändringar av data och lämna de slutliga resultaten inkonsekventa. För att garantera att operationerna förblir isolerade använder SQL Server låsmekanismer.
Låslägen och hierarki
SQL Servers mekanism för samtidighetskontroll är inblandad. För att optimera prestandan när det gäller låsväntningar, dödlägen och liknande måste du fatta ett beslut baserat på det specifika scenariot.
I SQL Server kan lås hållas på olika sätt och på flera nivåer av granularitet. Låslägen är de specifika sätten att göra detta, och deras nivåer är låshierarki.
Figur 1 visar de låslägen som är tillgängliga i SQL Server för standardnivån för transaktionsisolering (READ COMMITTED):
Översikt över låseskalering
SQL Server kan låsa resurser på flera nivåer. Det beror på de mest effektiva åtgärderna beroende på vilken typ av arbetsbelastning. Tabell 1 visar de resurser som kan låsas.
- Lås på en mer granulär nivå (t.ex. radnivålås) tillåter högre samtidighet och mindre blockering.
- Lås på en högre nivå (t.ex. Bordsnivålås) minskar samtidighet. De kan orsaka mer blockering, beroende på hur länge det faktiska uttalandet varar.
SQL Server väljer den nödvändiga låsningsnivån enligt interna mått.
En låseskalering inträffar när ett lås konverteras från en finare nivå av granularitet till en grövre nivå.
T.ex. konvertera ett radlås till ett tabelllås (se tabell 1).
Resurs | Beskrivning |
RID | Radidentifieraren som används för att låsa en enskild rad i en hög. |
NYCKEL | Radlåset i ett index som används för att skydda nyckelintervall i serialiserbara transaktioner. |
SIDA | 8-kilobyte (KB)-sidan i en databas, till exempel data eller indexsidor. |
OMRÄCKNING | Den sammanhängande gruppen med åtta sidor, till exempel data- eller indexsidor. |
HoBT | Högen eller B-trädet. Låset skyddar ett B-träd (index) eller heapdatasidorna i en tabell som inte har ett klustrat index. |
TABELL | Hela tabellen, inklusive alla data och index. |
FIL | Databasfilen. |
APPLIKATION | Den programspecificerade resursen. |
METADATA | Metadatalås. |
ALLOCATION_UNIT | Tilldelningsenheten. |
DATABAS | Hela databasen. |
Bakgrunden till låseskalering
Lås i SQL Server kan vara ganska dyra. För varje lås som låshanteraren skaffar måste SQL Server reservera minne – 64 byte eller 128 byte. Beloppet beror på om vi har att göra med ett 32-bitars respektive 64-bitars system.
När antalet radlås på en tabell ökar måste SQL Server skaffa mer och mer minne. Därför svälter andra processer, utan minne.
Det är vettigt att konvertera radlås och sidlås till ett lås på en tabell (objekt)nivå. Det händer när antalet lås för den tabellen överstiger 5000.
Kompromissen inträffar när hela tabellen inte längre är tillgänglig för andra sessioner i transaktionsprocessen.
Demonstrera låseskalering
Vi kan demonstrera låseskalering med koden i lista 1.
Låt oss först beskriva tabellen lite. Produktion.ProdukterI är ett relativt litet bord med cirka 7777 rader. Byggnadselementen är samma uppsättning av 77 rader duplicerade 101 gånger. Koden i lista 1 består av tre versioner av samma uppdateringsutlåtande, var och en inkluderad i en transaktion.
-- Listing 1: Demonstrating Lock Escalation
-- Update very few rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00'
WHERE unitprice='18.00';
ROLLBACK
-- Update a large number of rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00'
WHERE unitprice>'18.00';
ROLLBACK
-- Update over 5000 rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00';
ROLLBACK
För mer klarhet kommer vi att dela upp innehållet i lista 1.
Innan det, låt oss observera Listing 2 - en fråga för att visa låsen som finns i TSQLV4-databasen.
Vår första åtgärd är att utföra listning 1a. Sedan använder vi Listing 2 för att undersöka hur låshanteraren utför låsning i scenariot. Vi exekverar listning 1a utan att utfärda rollback-satsen. På så sätt bevarar vi låsen tillräckligt länge så att frågan i Lista 2 kan fånga dem.
-- Listing 1a: Demonstrating Lock Escalation
-- Update very few rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00'
WHERE unitprice='18.00';
ROLLBACK
-- Listing 2: Displaying Locks Held in Database TSQLV4
USE TSQLV4
GO
SELECT
resource_type
, DB_NAME (resource_database_id) database_name
--, OBJECT_NAME(resource_associated_entity_id) resource_name
, request_mode
, request_type
, request_status
, request_reference_count
, request_session_id
, resource_associated_entity_id
, OBJECT_NAME(resource_associated_entity_id) [object_name] --small obj ids
, getuser.login_name
FROM sys.dm_tran_locks
CROSS APPLY dmv.dbo.getuser(request_session_id) as getuser
WHERE DB_NAME (resource_database_id)='TSQLV4';
När vi kör frågan i Listing 1a och sedan kontrollerar låsen med hjälp av frågan i Listing 2, returnerar SQL Server resultatet som visas i Figur 2.
404 rader i tabellen har unitprice=’18.00’ . Låshanteraren låser dessa rader tillsammans med andra lås på vilken nivå som helst. Det bringar antalet rader i figur 2 till 467.
-- Listing 1b: Demonstrating Lock Escalation
-- Update a large number of rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00'
WHERE unitprice>'18.00';
ROLLBACK
Vi observerar liknande beteende när vi kör frågan i Lista 1b. Den här gången har vi att göra med 4406 rader. Det återspeglar antalet rader i tabellen Produktion. ProduktI med enhetspris>18,00.
-- Listing 1c: Demonstrating Lock Escalation
-- Update over 5000 rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00';
ROLLBACK
När vi går vidare och exekverar koden i Listing 1c ser vi ett annat beteende (se figur 4).
Lista 1c försöker uppdatera alla 7777 rader i tabellen Production.ProductI. SQL Server fastställer att det inte längre är effektivt att låsa så många rader för att garantera isolering. Istället är hela bordet låst.
Mer om låseskalering
Tabelllåset innebär att ingen annan session kan ändra sina rader under transaktionens varaktighet, vilket kan hända även när en blockeringssession inte manipulerar alla rader i tabellen.
Det är också värt att nämna att andra faktorer kan påverka hur lås förvärvas och eskaleras i SQL Server. Dessa är de konfigurerade isoleringsnivåerna, indexering och spårningsflaggor.
Spårningsflaggor T1211 och T1224 kan användas för att inaktivera låseskalering helt. Lock Eskalering kan också inaktiveras och aktiveras för en specifik tabell med följande kod:
-- Listing 5: Disable and Enable Lock Escalation
ALTER TABLE Production.ProductsI SET (LOCK_ESCALATION=DISABLE);
ALTER TABLE Production.ProductsI SET (LOCK_ESCALATION=TABLE);
Man kanske vill göra det för att minska blockering associerad låsning av hela bordet. På grund av påverkan på minnet bör det övervägas som en tillfällig åtgärd.
Slutsats
SQL Server använder Lock Escalation för att kontrollera effekten av mer granulär låsning på serverresurser. För att visa hur dessa lås förekommer – radlås, sidlås, objektlås etc. – fråga i den dynamiska hanteringsvyn sys.dm_tran_locks. Den ger mycket information om låsning, förutom Lock Escalation.
Även om det är möjligt att manipulera låshanterarens beteende, är det viktigt att göra det med stor försiktighet. Det är också viktigt att känna till den exakta prestandaeffekten av alla ansträngningar för att göra sådana ändringar.
Referenser
- Korotkevitch, D., 2016. Pro SQL Server Internals. Florida:Dmitri Korotkevitch
- Lås scenarier med Sys.dm_tran_locks
- Transaktionslåsning och radversionsguide