Úvod
Relační databáze sledují vlastnosti ACID v tom, jak implementují transakce – atomicita, konzistence, izolace a trvanlivost. Izolace je nezbytná k zajištění toho, že více transakcí nemůže způsobit změny v datech a ponechat konečné výsledky nekonzistentní. Aby bylo zaručeno, že operace zůstanou izolované, SQL Server používá uzamykací mechanismy.
Režimy a hierarchie uzamčení
Je zapojen mechanismus SQL Server pro kontrolu souběžnosti. Chcete-li optimalizovat výkon z hlediska čekání na uzamčení, uváznutí a podobně, musíte se rozhodnout na základě konkrétního scénáře.
Na serveru SQL Server lze zámky držet různými způsoby a na několika úrovních granularity. Režimy zámku jsou specifické způsoby, jak to udělat, a jejich úrovně jsou Hierarchie zámku.
Obrázek 1 ukazuje režimy uzamčení dostupné na serveru SQL Server pro výchozí úroveň izolace transakcí (READ COMMITTED):
Přehled eskalace uzamčení
SQL Server může uzamknout prostředky na několika úrovních. Záleží na nejúčinnějších úkonech podle charakteru pracovní zátěže. Tabulka 1 ukazuje prostředky, které lze uzamknout.
- Zámky na podrobnější úrovni (např. zámky na úrovni řádků) umožňují vyšší souběžnost a méně blokování.
- Zámky na vyšší úrovni (např. zámek na úrovni tabulky) snižují souběžnost. Mohou způsobit další blokování v závislosti na tom, jak dlouho aktuální výpis trvá.
SQL Server vybere potřebnou úroveň zamykání podle interních metrik.
Eskalace zámku nastane, když je zámek převeden z jemnější úrovně granularity na hrubší úroveň.
Např. převod zámku řádku na zámek tabulky (viz tabulka 1).
Zdroj | Popis |
RID | Identifikátor řádku používaný k uzamčení jednoho řádku v hromadě. |
KEY | Zámek řádku v rámci indexu používaný k ochraně rozsahů klíčů v serializovatelných transakcích. |
STRÁNKA | 8kilobajtová (KB) stránka v databázi, jako jsou datové nebo indexové stránky. |
EXTENT | Souvislá skupina osmi stránek, jako jsou datové stránky nebo stránky indexu. |
HoBT | Hromady nebo B-strom. Zámek chrání B-strom (index) nebo datové stránky haldy v tabulce, která nemá seskupený index. |
TABULKA | Celá tabulka, včetně všech dat a indexů. |
SOUBOR | Soubor databáze. |
APLIKACE | Prostředek specifikovaný aplikací. |
METADATA | Zámky metadat. |
ALLOCATION_UNIT | Alokační jednotka. |
DATABÁZE | Celá databáze. |
Důvod pro eskalaci uzamčení
Zámky v SQL Server mohou být poměrně drahé. Pro každý zámek, který Správce zámků získá, musí SQL Server vyhradit paměť – 64 bajtů nebo 128 bajtů. Částka závisí na tom, zda se jedná o 32bitový nebo 64bitový systém.
S rostoucím počtem zámků řádků v tabulce musí SQL Server získávat stále více paměti. Proto ostatní procesy hladovějí, nemají paměť.
Má smysl převést zámky řádků a zámky stránek na zámek na úrovni jedné tabulky (objektu). Stává se to, když počet zámků pro tuto tabulku překročí 5000.
Kompromis nastane, když celá tabulka již není dostupná pro ostatní relace v procesu transakce.
Ukázka eskalace uzamčení
Eskalaci zámku můžeme demonstrovat pomocí kódu ve výpisu 1.
Nejprve si tabulku trochu popišme. Produkce.ProduktyI je relativně malý stůl s asi 7777 řádky. Stavební prvky jsou stejné sady 77 řad duplikovaných 101krát. Kód v výpisu 1 se skládá ze tří verzí stejného aktualizačního prohlášení, z nichž každá je součástí transakce.
-- 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
Pro větší přehlednost rozebereme obsah výpisu 1.
Předtím se podívejme na výpis 2 – dotaz na zobrazení zámků držených v databázi TSQLV4.
Naší první akcí je provedení výpisu 1a. Poté použijeme Výpis 2, abychom prozkoumali, jak Správce zámků provádí zamykání ve scénáři. Provedeme výpis 1a bez vydání příkazu vrácení. Tímto způsobem zachováme zámky dostatečně dlouho, aby je mohl zachytit dotaz ve výpisu 2.
-- 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';
Když spustíme dotaz ve výpisu 1a a poté zkontrolujeme zámky pomocí dotazu ve výpisu 2, SQL Server vrátí výsledek zobrazený na obrázku 2.
404 řádků v tabulce má unitprice=’18,00’ . Správce zámků uzamkne tyto řádky spolu s ostatními zámky jakékoli potřebné úrovně. Tím se počet řádků na obrázku 2 zvýší na 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
Podobné chování pozorujeme, když provádíme dotaz ve výpisu 1b. Tentokrát máme co do činění s 4406 řádky. Odráží počet řádků v tabulce Production.ProductI s jednotkovou cenou>18,00.
-- Listing 1c: Demonstrating Lock Escalation
-- Update over 5000 rows
BEGIN TRAN
use TSQLV4
GO
UPDATE Production.ProductsI SET unitprice='100.00';
ROLLBACK
Když půjdeme dále a spustíme kód ve výpisu 1c, uvidíme jiné chování (viz obrázek 4).
Výpis 1c se pokusí aktualizovat všech 7777 řádků v tabulce Production.ProductI. SQL Server zjistí, že uzamčení tolika řádků již není efektivní pro zajištění izolace. Místo toho je celý stůl uzamčen.
Další informace o eskalaci uzamčení
Zámek tabulky znamená, že žádná jiná relace nemůže upravovat její řádky po dobu trvání transakce, k čemuž může dojít, i když blokující relace nemanipuluje se všemi řádky v tabulce.
Za zmínku také stojí, že způsob získávání a eskalování zámků v SQL Server mohou ovlivnit další faktory. Toto jsou konfigurovaná úroveň izolace, indexování a příznaky trasování.
Příznaky trasování T1211 a T1224 lze použít k úplnému zakázání eskalace zámku. Eskalaci zámku lze také zakázat a povolit pro konkrétní tabulku pomocí následujícího kódu:
-- Listing 5: Disable and Enable Lock Escalation
ALTER TABLE Production.ProductsI SET (LOCK_ESCALATION=DISABLE);
ALTER TABLE Production.ProductsI SET (LOCK_ESCALATION=TABLE);
Někdo to možná bude chtít udělat, aby se snížilo blokování spojené s uzamčením celé tabulky. Vzhledem k dopadu na paměť je třeba zvážit dočasné opatření.
Závěr
SQL Server používá eskalaci uzamčení k řízení dopadu podrobnějšího zamykání na prostředky serveru. Chcete-li zobrazit způsob výskytu těchto zámků – zámky řádků, zámky stránek, zámky objektů atd. – dotazujte se v pohledu dynamické správy sys.dm_tran_locks. Poskytuje mnoho informací o zamykání, kromě Eskalace zámku.
I když je možné manipulovat s chováním Správce zámků, je nezbytné to dělat s velkou opatrností. Je také důležité znát přesný dopad na výkon jakéhokoli úsilí zaměřeného na provedení takových úprav.
Odkazy
- Korotkevitch, D., 2016. Pro SQL Server Internals. Florida:Dmitrij Korotkevitch
- Zamknout scénáře pomocí Sys.dm_tran_locks
- Průvodce zamykáním transakcí a verzováním řádků