Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Analytics Platform System (PDW)
SQL Database w Microsoft Fabric
W tym artykule szczegółowo omówiono zakleszczenia w silniku bazy danych. Zakleszczenia są spowodowane przez konkurencyjne, współbieżne blokady w bazie danych, często w transakcjach wieloetapowych. Aby uzyskać więcej informacji na temat transakcji i blokad, zobacz Transaction locking and row versioning guide (Przewodnik dotyczący blokowania transakcji i przechowywania wersji wierszy).
Aby uzyskać bardziej szczegółowe informacje na temat identyfikacji i zapobiegania zakleszczeniom w usłudze Azure SQL Database i bazie danych SQL w sieci szkieletowej, zobacz Analizowanie i zapobieganie zakleszczeniom w usłudze Azure SQL Database i bazie danych SQL w usłudze Fabric.
Zrozumienie zakleszczeń
Zakleszczenie występuje, gdy co najmniej dwa zadania trwale blokują się nawzajem, ponieważ każde z nich posiada blokadę na zasobie, który próbują zablokować inne zadania. Przykład:
Transaction A uzyskuje współdzieloną blokadę w wierszu 1.
Transakcja B uzyskuje współdzieloną blokadę w wierszu 2.
Transakcja A wymaga teraz wyłącznej blokady na wierszu 2 i jest blokowana do momentu zakończenia transakcji B oraz zwolnienia blokady współdzielonej, jaką ma na wierszu 2.
Transakcja B żąda teraz wyłącznej blokady na wierszu 1 i jest blokowana do momentu zakończenia transakcji A, która zwolni udostępnioną blokadę na wierszu 1.
Transakcja A nie może zakończyć się, dopóki transakcja B nie zostanie ukończona, ale transakcja B zostanie zablokowana przez transakcję A. Ten warunek jest również nazywany cykliczną zależnością: Transakcja A ma zależność od transakcji B, a transakcja B zamyka koło, mając zależność od transakcji A.
Obie transakcje w impasie oczekują w nieskończoność, dopóki zakleszczenie nie zostanie usunięte przez proces zewnętrzny. Monitor zakleszczeń silnika bazy danych okresowo sprawdza zadania, które znajdują się w zakleszczeniu. Jeśli monitor wykryje zależność cykliczną, wybiera jedno z zadań jako ofiarę i kończy transakcję z błędem. Dzięki temu inne zadanie może zakończyć swoją transakcję. Aplikacja z transakcją, która zakończyła się z błędem, może ponowić próbę transakcji, która zwykle kończy się po zakończeniu innej zakleszczonej transakcji.
Zakleszczenie jest często mylone z normalnym blokowaniem. Gdy transakcja żąda zablokowania zasobu przez inną transakcję, transakcja żądająca czeka na odblokowanie zasobu. Domyślnie transakcje w silniku bazy danych nie tracą ważności czasowej, chyba że LOCK_TIMEOUT jest ustawione. Żądana transakcja jest zablokowana, a nie zakleszczona, ponieważ żądająca transakcja nie wykonała żadnych działań, aby zablokować transakcję będącą właścicielem blokady. W końcu transakcja będąca właścicielem kończy i zwalnia blokadę, a następnie żądana transakcja otrzymuje blokadę i przechodzi dalej. Zakleszczenia są rozwiązywane niemal natychmiast, podczas gdy blokowanie może, teoretycznie, utrzymywać się na czas nieokreślony. Zakleszczenia są czasami nazywane śmiertelnym uściskiem.
Zakleszczenie może wystąpić w dowolnym systemie z wieloma wątkami, nie tylko w systemach zarządzania relacyjnymi bazami danych, i może dotyczyć zasobów innych niż blokady obiektów bazy danych. Na przykład, wątek w wielowątkowym systemie operacyjnym może uzyskać jeden lub więcej zasobów, takich jak bloki pamięci. Jeśli pozyskany zasób jest obecnie własnością innego wątku, pierwszy wątek może być musiał poczekać, aż wątek będący właścicielem zwolni zasób docelowy. Mówi się, że wątek oczekiwania jest zależny od wątku właściciela dla danego zasobu. W przypadku wystąpienia silnika bazy danych sesje mogą utknąć w zakleszczeniu podczas uzyskiwania zasobów innych niż baza danych, takich jak pamięć lub wątki.
Na ilustracji transakcja T1 ma zależność od transakcji T2 dla Part zasobu blokady tabeli. Podobnie transakcja T2 ma zależność od transakcji T1 dla Supplier zasobu blokady tabeli. Ponieważ te zależności tworzą cykl, istnieje impas między transakcjami T1 i T2.
Oto bardziej ogólna ilustracja zakleszczenia:
Zadanie T1 ma blokadę na zasobie R1 (wskazywaną przez strzałkę z R1 do T1) i zażądało blokady na zasobie R2 (wskazywaną przez strzałkę od T1 do R2).
Zadanie T2 ma blokadę na zasobie R2 (wskazywaną przez strzałkę z R2 do T2) i zażądało blokadę na zasobie R1 (wskazywaną przez strzałkę z T2 do R1).
Ponieważ żadne zadanie nie może być kontynuowane, dopóki zasób nie będzie dostępny i żaden zasób nie może zostać zwolniony do momentu kontynuowania zadania, istnieje stan zakleszczenia.
Note
Aparat bazy danych automatycznie wykrywa cykle zakleszczenia. Wybiera jedną z transakcji jako ofiarę zakleszczenia i kończy ją błędem, aby przerwać impas.
Zasoby, które mogą doprowadzić do zakleszczenia
Każda sesja użytkownika może mieć jedno lub więcej zadań działających w jego imieniu, gdzie każde z nich może uzyskiwać lub oczekiwać na uzyskanie zasobów. Następujące typy zasobów mogą spowodować zablokowanie, które może spowodować zakleszczenie.
Locks. Oczekiwanie na uzyskanie blokad zasobów, takich jak obiekty, strony, wiersze, metadane i aplikacje, może spowodować zakleszczenie. Na przykład transakcja T1 ma udostępnioną blokadę (
S) w wierszu r1 i oczekuje na uzyskanie wyłącznej blokady (X) na r2. Transakcja T2 ma udostępnioną blokadę (S) na r2 i oczekuje na uzyskanie wyłącznej blokady (X) w wierszu r1. Powoduje to cykl blokady, w którym T1 i T2 czekają na siebie, aby zwolnić zablokowane zasoby.Wątki robocze. Zadanie w kolejce czekające na dostępny wątek roboczy może spowodować zakleszczenie. Jeśli zadanie w kolejce jest właścicielem zasobów, które blokują wszystkie wątki robocze, rezultatem jest zakleszczenie. Na przykład sesja S1 uruchamia transakcję i uzyskuje udostępnioną blokadę (
S) w wierszu r1, a następnie przechodzi w stan uśpienia. Aktywne sesje uruchomione we wszystkich dostępnych wątkach roboczych próbują uzyskać wyłączne blokady (X) w wierszu r1. Ponieważ sesja S1 nie może uzyskać wątku roboczego, nie może zatwierdzić transakcji i zwolnić blokadę w wierszu r1. Powoduje to zakleszczenie.Memory. Gdy współbieżne żądania oczekują na przydziały pamięci, których nie można zrealizować przy dostępnej pamięci, może dojść do zakleszczenia. Na przykład dwa współbieżne zapytania, Q1 i Q2, są wykonywane jako funkcje zdefiniowane przez użytkownika, które uzyskują odpowiednio 10 MB i 20 MB pamięci. Jeśli każde zapytanie wymaga 30 MB, a łączna ilość dostępnej pamięci wynosi 20 MB, wówczas q1 i Q2 muszą poczekać na zwolnienie pamięci, co powoduje zakleszczenie.
Zasoby związane z wykonywaniem zapytań równoległych. Wątki koordynatora, producenta lub odbiorcy skojarzone z portem wymiany mogą blokować się nawzajem, co zwykle powoduje zakleszczenie w przypadku dołączania co najmniej jednego innego procesu, który nie jest częścią zapytania równoległego. Ponadto po rozpoczęciu wykonywania zapytania równoległego aparat bazy danych określa stopień równoległości i liczbę wymaganych wątków roboczych na podstawie bieżącego obciążenia. Jeśli obciążenie systemowe nieoczekiwanie ulegnie zmianie, na przykład gdy nowe zapytania zaczynają działać na serwerze lub system zabraknie wątków roboczych, może wystąpić zakleszczenie.
Zasoby wielu aktywnych zestawów wyników (MARS). Te zasoby służą do kontrolowania przeplatania wielu aktywnych żądań w ramach usługi MARS. Aby uzyskać więcej informacji, zobacz Using Multiple Active Result Sets (MARS) in SQL Server Native Client.
Zasób użytkownika. Gdy wątek czeka na zasób, który jest potencjalnie kontrolowany przez aplikację użytkownika, zasób jest uważany za za zasób zewnętrzny lub użytkownika i jest traktowany jak blokada.
Mutex sesji. Zadania uruchomione w jednej sesji są przeplatane, co oznacza, że tylko jedno zadanie może być uruchamiane w ramach danej sesji. Przed uruchomieniem zadania musi mieć wyłączny dostęp do mutexu sesji.
Mutex transakcji. Wszystkie zadania uruchomione w jednej transakcji są przeplatane, co oznacza, że tylko jedno zadanie może być uruchamiane w ramach transakcji w danym momencie. Zanim zadanie będzie mogło się uruchomić, musi mieć wyłączny dostęp do mutexu transakcji.
Aby zadanie było uruchamiane w ramach usługi MARS, musi uzyskać mutex sesji. Jeśli zadanie działa w ramach transakcji, musi następnie uzyskać mutex transakcji. Gwarantuje to, że tylko jedno zadanie jest aktywne jednocześnie w danej sesji i danej transakcji. Po uzyskaniu wymaganych muteksów zadanie może zostać wykonane. Gdy zadanie zakończy się lub zwraca w środku żądania, najpierw zwalnia mutex transakcji, a następnie mutex sesji, w odwrotnej kolejności pozyskiwania. Jednak zakleszczenia mogą wystąpić w przypadku tych zasobów. W poniższym pseudokodzie dwa zadania, żądanie użytkownika U1 i żądanie użytkownika U2, są uruchomione w tej samej sesji.
U1: Rs1=Command1.Execute("insert sometable EXEC usp_someproc"); U2: Rs2=Command2.Execute("select colA from sometable");Procedura składowana wykonująca żądanie użytkownika U1 uzyskała mutex sesji. Jeśli wykonanie procedury składowanej trwa długo, przyjmuje się, że aparat bazy danych oczekuje na dane wejściowe od użytkownika. Żądanie użytkownika U2 czeka na mutex sesji, podczas gdy użytkownik oczekuje na zestaw wyników od U2, a U1 oczekuje na zasób użytkownika. Jest to stan zakleszczenia zilustrowany logicznie jako:
Zakleszczenia mogą również wystąpić, gdy tabela jest partycjonowana, a ustawienie LOCK_ESCALATION dla ALTER TABLE ma wartość AUTO. Gdy LOCK_ESCALATION jest ustawiona wartość AUTO, współbieżność zwiększa się, pozwalając silnikowi bazy danych na blokowanie partycji tabeli na poziomie HoBT zamiast na poziomie tabeli. Jednak gdy oddzielne transakcje przechowują blokady partycji w tabeli i chcą zablokować gdzieś na innej partycji transakcji, powoduje to zakleszczenie. Tego typu zakleszczenia można uniknąć, ustawiając LOCK_ESCALATION na TABLE. Jednak to ustawienie zmniejsza współbieżność, zmuszając duże aktualizacje partycji do oczekiwania na blokadę tabeli.
Wykrywanie zakleszczeń
Wszystkie zasoby wymienione w sekcji Zasoby, które mogą powodować zakleszczenia uczestniczą w schemacie wykrywania zakleszczeń silnika bazy danych. Wykrywanie zakleszczenia jest wykonywane przez wątek monitorowania blokady, który okresowo inicjuje przeszukiwanie wszystkich zadań w wystąpieniu silnika bazy danych. W poniższych punktach opisano proces wyszukiwania:
Domyślny interwał to 5 sekund.
Jeśli wątek monitora blokady znajdzie zakleszczenia, interwał wykrywania zakleszczenia spadnie z 5 sekund do nawet 100 milisekund w zależności od częstotliwości zakleszczenia.
Jeśli wątek monitora blokady przestanie wykrywać zakleszczenia, silnik bazy danych zwiększa odstępy między wyszukiwaniami do 5 sekund.
Jeśli wykryte zostanie zakleszczenie, zakłada się, że nowe wątki, które muszą czekać na blokadę, dołączają do cyklu zakleszczenia. Pierwsze kilka oczekiwań na blokady po wykryciu zakleszczenia natychmiast wyzwala natychmiastowe wyszukiwanie zakleszczeń, zamiast czekać na kolejny interwał wykrywania zakleszczeń. Jeśli na przykład bieżący interwał wynosi 5 sekund, a wykryto zakleszczenie, następne oczekiwanie na blokadę natychmiast uruchamia detektor zakleszczeń. Jeśli to oczekiwanie na blokadę jest częścią zakleszczenia, zostanie wykryte od razu, a nie podczas następnego wyszukiwania zakleszczenia.
Silnik bazy danych zwykle wykonuje tylko okresowe wykrywanie zakleszczenia. Ponieważ liczba zakleszczeń napotkanych w systemie jest zwykle niewielka, okresowe wykrywanie zakleszczeń pomaga zmniejszyć obciążenie związane z ich wykrywaniem w systemie.
Gdy monitor blokady inicjuje wyszukiwanie zakleszczenia dla określonego wątku, identyfikuje zasób, na którym czeka wątek. Monitor blokady znajduje następnie właścicieli tego konkretnego zasobu i cyklicznie kontynuuje wyszukiwanie zakleszczenia dla tych wątków, dopóki nie znajdzie cyklu. Cykl zidentyfikowany w ten sposób stanowi impas.
Po wykryciu zakleszczenia silnik bazy danych rozwiązuje zakleszczenie, wybierając jeden z wątków jako ofiarę. Silnik bazy danych kończy bieżącą partię wykonywaną w ramach wątku, cofa transakcję jako ofiary zakleszczenia i zwraca aplikacji błąd 1205. Wycofanie transakcji dla ofiary zakleszczenia zwalnia wszystkie blokady przechowywane przez transakcję. Dzięki temu transakcje innych wątków staną się odblokowane i będą kontynuowane. Błąd 1205 (ofiara zakleszczenia) rejestruje informacje o typie zasobów zaangażowanych w zakleszczenie.
Domyślnie aparat bazy danych wybiera transakcję uruchamiającą transakcję, która jest najmniej kosztowna do wycofania jako ofiara zakleszczenia. Alternatywnie, użytkownik może określić priorytet sesji w sytuacji zakleszczenia, korzystając z instrukcji SET DEADLOCK_PRIORITY.
DEADLOCK_PRIORITY można ustawić na LOW, NORMAL, lub HIGH, lub alternatywnie na dowolną wartość całkowitą w zakresie od -10 do 10. W niektórych przypadkach mechanizm bazy danych może tymczasowo zmienić priorytet zakleszczenia, aby osiągnąć lepszą współbieżność.
Priorytet zakleszczenia jest domyślnie ustawiony na NORMAL lub na 0. Jeśli dwie sesje mają różne priorytety zakleszczenia, transakcja w sesji o niższym priorytecie zostanie wybrana jako ofiara zakleszczenia. Jeśli obie sesje mają taki sam priorytet zakleszczenia, wybierana jest transakcja, której wycofanie jest najmniej kosztowne. Jeśli sesje uczestniczące w cyklu zakleszczenia mają taki sam priorytet zakleszczenia i ten sam koszt, ofiara zostanie wybrana losowo. Nie można wybrać zadania, które cofa się jako ofiara impasu.
Podczas pracy ze środowiskiem uruchomieniowym języka wspólnego (CLR), monitor zakleszczeń automatycznie wykrywa zakleszczenia w zasobach synchronizacji (monitorów, blokady do odczytu/zapisu i łączenia wątków) używanych wewnątrz procedur zarządzanych. Jednak zakleszczenie jest rozwiązywane przez zgłoszenie wyjątku w procedurze, która została wybrana jako ofiara zakleszczenia. Ważne jest, aby zrozumieć, że wyjątek nie zwalnia automatycznie zasobów, które są obecnie własnością ofiary; zasoby muszą zostać jawnie zwolnione. Zgodnie z zachowaniem wyjątku wyjątek używany do identyfikowania ofiary zakleszczenia można przechwycić i odrzucić.
Narzędzia do informacji o zakleszczeniach
Aby wyświetlić informacje o zakleszczeniu, silnik bazy danych udostępnia narzędzia monitorujące w postaci rozszerzonego zdarzenia xml_deadlock_report, dwóch flag śledzenia oraz zdarzenia grafu zakleszczenia w SQL Profiler.
Zdarzenie xml_deadlock_report rozszerzone jest zalecaną metodą przechwytywania informacji o impasie.
Zdarzenie zakleszczenia rozszerzone
W SQL Server 2012 (11.x) i późniejszych wersjach należy używać xml_deadlock_report zdarzenia rozszerzonego zamiast klasy zdarzeń grafu zakleszczeń w SQL Trace lub SQL Profiler.
Sesja zdarzeń system_health przechwytuje domyślnie xml_deadlock_report zdarzenia. Te zdarzenia zawierają wykres zakleszczenia. Ponieważ sesja system_health jest domyślnie włączona, nie trzeba konfigurować oddzielnej sesji zdarzeń w celu przechwytywania informacji o zakleszczeniach.
Przechwycony graf zakleszczenia zwykle ma trzy odrębne węzły:
-
victim-list. Identyfikator procesu ofiary zakleszczenia. -
process-list. Informacje o wszystkich procesach związanych z zablokowaniem. -
resource-list. Informacje na temat zasobów zaangażowanych w zakleszczenie.
Dane docelowe event_file sesji można wyświetlić w programie system_health Management Studio. Jeśli wystąpiły jakiekolwiek xml_deadlock_report zdarzenia, program Management Studio przedstawia graficzne przedstawienie zadań i zasobów związanych z zakleszczeniem, jak pokazano w poniższym przykładzie:
Następujące zapytanie może wyświetlić wszystkie zdarzenia zakleszczenia przechwycone przez ring_buffer element docelowy system_health sesji:
SELECT xdr.value('@timestamp', 'datetime') AS deadlock_time,
xdr.query('.') AS event_data
FROM (SELECT CAST ([target_data] AS XML) AS target_data
FROM sys.dm_xe_session_targets AS xt
INNER JOIN sys.dm_xe_sessions AS xs
ON xs.address = xt.event_session_address
WHERE xs.name = N'system_health'
AND xt.target_name = N'ring_buffer') AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr)
ORDER BY deadlock_time DESC;
Oto zestaw wyników.
Poniższy przykład przedstawia przykładowe dane wyjściowe z kolumny event_data :
<event name="xml_deadlock_report" package="sqlserver" timestamp="2022-02-18T08:26:24.698Z">
<data name="xml_report">
<type name="xml" package="package0" />
<value>
<deadlock>
<victim-list>
<victimProcess id="process27b9b0b9848" />
</victim-list>
<process-list>
<process id="process27b9b0b9848" taskpriority="0" logused="0" waitresource="KEY: 5:72057594214350848 (1a39e6095155)" waittime="1631" ownerId="11088595" transactionname="SELECT" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27b9f79fac0" lockMode="S" schedulerid="9" kpid="15336" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2022-02-18T00:26:22.893" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="7908" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088595" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
<executionStack>
<frame procname="AdventureWorks2022.dbo.p1" line="3" stmtstart="78" stmtend="180" sqlhandle="0x0300050020766505ca3e07008ba8000001000000000000000000000000000000000000000000000000000000">
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+ </frame>
<frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x020000006263ec01ebb919c335024a072a2699958d3fcce60000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
EXEC p1 4
END
</inputbuf>
</process>
<process id="process27b9ee33c28" taskpriority="0" logused="252" waitresource="KEY: 5:72057594214416384 (e5b3d7e750dd)" waittime="1631" ownerId="11088593" transactionname="UPDATE" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27ba15a4490" lockMode="X" schedulerid="6" kpid="5584" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-02-18T00:26:22.890" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="15316" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088593" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
<executionStack>
<frame procname="AdventureWorks2022.dbo.p2" line="3" stmtstart="76" stmtend="150" sqlhandle="0x03000500599a5906ce3e07008ba8000001000000000000000000000000000000000000000000000000000000">
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p </frame>
<frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x02000000008fe521e5fb1099410048c5743ff7da04b2047b0000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
EXEC p2 4
END
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594214350848" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="cidx" id="lock27b9dd26a00" mode="X" associatedObjectId="72057594214350848">
<owner-list>
<owner id="process27b9ee33c28" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process27b9b0b9848" mode="S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594214416384" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="idx1" id="lock27afa392600" mode="S" associatedObjectId="72057594214416384">
<owner-list>
<owner id="process27b9b0b9848" mode="S" />
</owner-list>
<waiter-list>
<waiter id="process27b9ee33c28" mode="X" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</value>
</data>
</event>
Flaga śledzenia 1204 i flaga śledzenia 1222
Po wystąpieniu zakleszczenia i włączeniu flagi śledzenia 1204 lub flagi śledzenia 1222 szczegóły zakleszczenia są zgłaszane w dzienniku błędów programu SQL Server. Flaga śledzenia 1204 zgłasza informacje o zakleszczeniach sformatowane przez każdy węzeł zaangażowany w zakleszczenie. Flaga 1222 formatuje informacje o zablokowaniach zasobów, najpierw według procesów, a potem według zasobów. Można włączyć obie flagi śledzenia, aby uzyskać dwie reprezentacje tego samego zdarzenia zakleszczenia.
Important
Unikaj używania flag śledzenia 1204 i 1222 w systemach o dużym obciążeniu, w których występują zakleszczenia. Użycie tych flag śledzenia może powodować problemy z wydajnością. Zamiast tego użyj rozszerzonego zdarzenia Deadlock, aby przechwycić niezbędne informacje.
Oprócz definiowania właściwości flag śledzenia 1204 i 1222 w poniższej tabeli przedstawiono również podobieństwa i różnice.
| Property | Flaga śledzenia 1204 i flaga śledzenia 1222 | Tylko flaga śledzenia 1204 | Tylko flaga śledzenia 1222 |
|---|---|---|---|
| Format wyjściowy | Dane wyjściowe są przechwytywane w dzienniku błędów programu SQL Server. | Koncentruje się na węzłach zaangażowanych w impas. Każdy węzeł ma dedykowaną sekcję, a ostatnia sekcja opisuje ofiarę zakleszczenia. | Zwraca informacje w formacie przypominającym XML, który nie jest zgodny ze schematem definicji schematu XML (XSD). Format zawiera trzy główne sekcje. Pierwsza sekcja deklaruje ofiarę zakleszczenia. W drugiej sekcji opisano każdy proces związany z impasem. W trzeciej sekcji opisano zasoby, które odpowiadają węzłom we fladze śledzenia 1204. |
| Identyfikowanie atrybutów |
SPID:<x> ECID:<x>. Identyfikuje wątek ID sesji w przypadkach procesów równoległych. Wpis SPID:<x> ECID:0, gdzie <x> jest zastępowany przez wartość SPID, reprezentuje główny wątek. Wpis SPID:<x> ECID:<y>, gdzie <x> jest zastępowany przez wartość SPID i <y> jest większy niż 0, reprezentuje kontekst wykonywania dla tego samego SPID.BatchID (sbid dla flagi śledzenia 1222). Określa partię, z której wykonywanie kodu żąda lub przechowuje blokadę. Po wyłączeniu wielu aktywnych zestawów wyników (MARS) wartość BatchID wynosi 0. Po włączeniu usługi MARS wartość aktywnych partii wynosi od 1 do n. Jeśli w sesji nie ma aktywnych partii, identyfikator BatchID to 0.Mode Określa typ blokady dla danego zasobu, który jest żądany, udzielony lub oczekiwany przez wątek. Tryb może być intencjonalnie udostępniony (IS), współdzielony (S), aktualizacyjny (U), intencjonalnie wyłączny (IX), współdzielony z intencjonalną wyłącznością (SIX) i wyłączny (X).Line # (line dla flagi śledzenia 1222). Wyświetla numer wiersza w bieżącym zestawie instrukcji wykonywanego w momencie wystąpienia zakleszczenia.Input Buf (inputbuf dla flagi śledzenia 1222). Wyświetla listę wszystkich wyrażeń w bieżącej partii. |
Node Reprezentuje numer wpisu w łańcuchu zakleszczenia.Lists Właściciel blokady może być częścią następujących list:Grant List Wylicza bieżących właścicieli zasobu.Convert List Wylicza bieżących właścicieli, którzy próbują zmienić poziom swoich blokad na wyższy.Wait List Wylicza bieżące nowe żądania blokady dla zasobu.Statement Type Opisuje typ instrukcji (SELECT, INSERT, UPDATElub DELETE), na której wątki mają uprawnienia.Victim Resource Owner Określa uczestniczący wątek, który aparat bazy danych wybiera jako ofiarę, aby przerwać cykl zakleszczenia. Wybrany wątek i wszystkie konteksty jego wykonywania są zakończone.Next Branch Reprezentuje dwa lub więcej konteksty wykonywania z tego samego SPID, które są zaangażowane w cykl zakleszczenia. |
deadlock victim Reprezentuje fizyczny adres pamięci zadania, które zostało wybrane jako ofiara zakleszczenia (zobacz sys.dm_os_tasks). Wartość może być równa zero w przypadku nierozwiązanego zakleszczenia.executionstack Reprezentuje stos wywołań Transact-SQL, który jest wykonywany w momencie wystąpienia zakleszczenia.priority Reprezentuje priorytet zakleszczenia.logused Miejsce w dzienniku używane przez zadanie.owner id Identyfikator transakcji, która ma kontrolę nad żądaniem.status Stan zadania. Aby uzyskać więcej informacji, zobacz sys.dm_os_tasks.waitresource Zasób wymagany przez zadanie.waittime Czas oczekiwania na zasób w milisekundach.schedulerid Harmonogram skojarzony z tym zadaniem. Zobacz sys.dm_os_schedulers.hostname Nazwa stacji roboczej.isolationlevel Bieżący poziom izolacji transakcji.Xactid Identyfikator transakcji, która ma kontrolę nad żądaniem.currentdb Identyfikator bazy danych.lastbatchstarted Ostatni raz proces klienta rozpoczął przetwarzanie wsadowe.lastbatchcompleted Ostatni raz, gdy proces klienta ukończył przetwarzanie wsadowe.clientoption1 i clientoption2 Ustawione opcje dla tej sesji. Te wartości to maski bitów reprezentujące opcje zwykle kontrolowane przez SET instrukcje, takie jak SET NOCOUNT i SET XACTABORT. Aby uzyskać więcej informacji, zobacz @@OPTIONS.associatedObjectId Reprezentuje identyfikator HoBT (stos lub drzewo B). |
| Atrybuty zasobów |
RID identyfikuje pojedynczy wiersz w tabeli, w której blokada jest przechowywana lub żądana. Identyfikator RID jest reprezentowany jako RID: db_id:file_id:page_no:row_no. Na przykład RID: 6:1:20789:0.OBJECT identyfikuje tabelę, na której blokada jest utrzymywana lub żądana.
OBJECT jest reprezentowany jako OBJECT: db_id:object_id. Na przykład TAB: 6:2009058193.KEY Określa zakres kluczy w indeksie, na którym blokada jest przechowywana lub żądana. KLUCZ jest reprezentowany jako KLUCZ: db_id:hobt_id (wartość skrótu klucza indeksu). Na przykład KEY: 6:72057594057457664 (350007a4d329).PAG Określa zasób strony, na którym blokada jest przechowywana lub żądana.
PAG jest reprezentowany jako PAG: db_id:file_id:page_no. Na przykład PAG: 6:1:20789.EXT Identyfikuje strukturę zakresu.
EXT jest reprezentowany jako EXT: db_id:file_id:extent_no. Na przykład EXT: 6:1:9.DB Identyfikuje blokadę bazy danych.
DB element jest reprezentowany w jeden z następujących sposobów:DB: db_idDB: db_id[BULK-OP-DB], który identyfikuje blokadę bazy danych wykonywaną podczas tworzenia kopii zapasowej bazy danych.DB: db_id[BULK-OP-LOG], który identyfikuje blokadę wykonywaną przez kopię zapasową dziennika.APP Identyfikuje blokadę aplikacji.
APP jest reprezentowany jako APP: lock_resource. Na przykład APP: Formf370f478.METADATA Reprezentuje zasoby metadanych związane z zakleszczeniem. Ponieważ METADATA ma wiele podzasobów, wartość zwracana zależy od podzasobu, który został zakleszczony. Na przykład METADATA.USER_TYPE zwraca wartość user_type_id = *integer_value*. Aby uzyskać więcej informacji o METADATA zasobach i zasobach podrzędnych, zobacz sys.dm_tran_locks.HOBT Reprezentuje stertę lub drzewo B związane z zakleszczeniem. |
Brak niczego wyłącznego dla tej flagi śledzenia. | Brak niczego wyłącznego dla tej flagi śledzenia. |
Przykład flagi śledzenia 1204
Poniższy przykład przedstawia dane wyjściowe po włączeniu flagi śledzenia 1204. W takim przypadku tabela w węźle 1 jest stertą bez indeksów, a tabela w węźle 2 jest stertą z indeksem nieklastrowanym. Klucz indeksu w węźle 2 jest aktualizowany po wystąpieniu zakleszczenia.
Deadlock encountered .... Printing deadlock information
Wait-for graph
Node:1
RID: 6:1:20789:0 CleanCnt:3 Mode:X Flags: 0x2
Grant List 0:
Owner:0x0315D6A0 Mode: X
Flg:0x0 Ref:0 Life:02000000 SPID:55 ECID:0 XactLockInfo: 0x04D9E27C
SPID: 55 ECID: 0 Statement Type: UPDATE Line #: 6
Input Buf: Language Event:
BEGIN TRANSACTION
EXEC usp_p2
Requested By:
ResType:LockOwner Stype:'OR'Xdes:0x03A3DAD0
Mode: U SPID:54 BatchID:0 ECID:0 TaskProxy:(0x04976374) Value:0x315d200 Cost:(0/868)
Node:2
KEY: 6:72057594057457664 (350007a4d329) CleanCnt:2 Mode:X Flags: 0x0
Grant List 0:
Owner:0x0315D140 Mode: X
Flg:0x0 Ref:0 Life:02000000 SPID:54 ECID:0 XactLockInfo: 0x03A3DAF4
SPID: 54 ECID: 0 Statement Type: UPDATE Line #: 6
Input Buf: Language Event:
BEGIN TRANSACTION
EXEC usp_p1
Requested By:
ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)
Victim Resource Owner:
ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)
Przykład flagi śledzenia 1222
Poniższy przykład przedstawia dane wyjściowe po włączeniu flagi śledzenia 1222. W takim przypadku jedna tabela jest stertą bez indeksów, a druga jest stertą z indeksem nieklastrowanym. W drugiej tabeli klucz indeksu jest aktualizowany, gdy występuje zakleszczenie.
deadlock-list
deadlock victim=process689978
process-list
process id=process6891f8 taskpriority=0 logused=868
waitresource=RID: 6:1:20789:0 waittime=1359 ownerId=310444
transactionname=user_transaction
lasttranstarted=2022-02-05T11:22:42.733 XDES=0x3a3dad0
lockMode=U schedulerid=1 kpid=1952 status=suspended spid=54
sbid=0 ecid=0 priority=0 transcount=2
lastbatchstarted=2022-02-05T11:22:42.733
lastbatchcompleted=2022-02-05T11:22:42.733
clientapp=Microsoft SQL Server Management Studio - Query
hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
isolationlevel=read committed (2) xactid=310444 currentdb=6
lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
executionStack
frame procname=AdventureWorks2022.dbo.usp_p1 line=6 stmtstart=202
sqlhandle=0x0300060013e6446b027cbb00c69600000100000000000000
UPDATE T2 SET COL1 = 3 WHERE COL1 = 1;
frame procname=adhoc line=3 stmtstart=44
sqlhandle=0x01000600856aa70f503b8104000000000000000000000000
EXEC usp_p1
inputbuf
BEGIN TRANSACTION
EXEC usp_p1
process id=process689978 taskpriority=0 logused=380
waitresource=KEY: 6:72057594057457664 (350007a4d329)
waittime=5015 ownerId=310462 transactionname=user_transaction
lasttranstarted=2022-02-05T11:22:44.077 XDES=0x4d9e258 lockMode=U
schedulerid=1 kpid=3024 status=suspended spid=55 sbid=0 ecid=0
priority=0 transcount=2 lastbatchstarted=2022-02-05T11:22:44.077
lastbatchcompleted=2022-02-05T11:22:44.077
clientapp=Microsoft SQL Server Management Studio - Query
hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
isolationlevel=read committed (2) xactid=310462 currentdb=6
lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
executionStack
frame procname=AdventureWorks2022.dbo.usp_p2 line=6 stmtstart=200
sqlhandle=0x030006004c0a396c027cbb00c69600000100000000000000
UPDATE T1 SET COL1 = 4 WHERE COL1 = 1;
frame procname=adhoc line=3 stmtstart=44
sqlhandle=0x01000600d688e709b85f8904000000000000000000000000
EXEC usp_p2
inputbuf
BEGIN TRANSACTION
EXEC usp_p2
resource-list
ridlock fileid=1 pageid=20789 dbid=6 objectname=AdventureWorks2022.dbo.T2
id=lock3136940 mode=X associatedObjectId=72057594057392128
owner-list
owner id=process689978 mode=X
waiter-list
waiter id=process6891f8 mode=U requestType=wait
keylock hobtid=72057594057457664 dbid=6 objectname=AdventureWorks2022.dbo.T1
indexname=nci_T1_COL1 id=lock3136fc0 mode=X
associatedObjectId=72057594057457664
owner-list
owner id=process6891f8 mode=X
waiter-list
waiter id=process689978 mode=U requestType=wait
Zdarzenie zakleszczenia grafu profilera
Program SQL Profiler ma zdarzenie przedstawiające graficzny obraz zadań i zasobów związanych z występującym zakleszczeniem. Poniższy przykład przedstawia dane wyjściowe z programu SQL Profiler po włączeniu zdarzenia grafu zakleszczenia.
Funkcje profilera SQL i śledzenia SQL są przestarzałe i zastępowane zdarzeniami rozszerzonymi. Zdarzenia rozszerzone mają mniejsze obciążenie związane z wydajnością i są bardziej konfigurowalne niż SQL Trace. Rozważ użycie zdarzenia zakleszczenia zdarzeń rozszerzonych zamiast śledzenia zakleszczeń w programie SQL Profiler.
Aby uzyskać więcej informacji na temat zdarzenia zakleszczenia, zobacz Lock:Deadlock Event Class. Aby uzyskać więcej informacji na temat wykresów zakleszczeń w SQL Profiler, zobacz Zapisywanie wykresów zakleszczeń (SQL Server Profiler).
Zdarzenia rozszerzone zapewniają odpowiedniki klas zdarzeń śledzenia SQL. Aby uzyskać więcej informacji, zobacz Wyświetlanie rozszerzonych zdarzeń równoważnych z klasami zdarzeń śledzenia SQL. Zaleca się korzystanie ze zdarzeń rozszerzonych zamiast SQL Trace.
Obsługa zakleszczeń
Gdy wystąpienie silnika bazy danych wybierze transakcję jako ofiarę deadlock, kończy bieżącą partię, cofa transakcję i zwraca błąd 1205 do aplikacji. Zwrócony komunikat jest ustrukturyzowany w następujący sposób:
Your transaction (process ID #...) was deadlocked on {lock | communication buffer | thread} resources with another process and has been chosen as the deadlock victim. Rerun your transaction.
Ponieważ wszystkie aplikacje przesyłające Transact-SQL zapytania mogą być wybierane jako ofiara zakleszczenia, aplikacje powinny mieć procedurę obsługi błędów, która może obsłużyć błąd 1205. Jeśli aplikacja nie obsługuje błędu, może działać dalej, nie będąc świadomą, że jej transakcja została cofnięta.
Zaimplementowanie procedury obsługi błędów, która przechwytuje błąd 1205, umożliwia aplikacji obsługę zakleszczeń i podjęcie akcji naprawczej (na przykład automatyczne ponowne przesłanie zapytania, które było związane z zakleszczeniem).
Aplikacja powinna zostać na krótko wstrzymana przed ponownym przesłaniem zapytania. Daje to drugiej transakcji biorącej udział w impasie szansę na ukończenie i zwolnienie jej blokad. Losowe określanie czasu trwania wstrzymania minimalizuje prawdopodobieństwo ponownego zakleszczenia, gdy ponownie zwrócone zapytanie żąda blokad. Na przykład procedura obsługi błędów może zostać zakodowana, aby zrobić pauzę na losowy okres od jednej do trzech sekund.
Obsługa za pomocą TRY...CATCH
Możesz użyć funkcji TRY... CATCH do obsługi zakleszczeń. Błąd 1205 może zostać przechwycony przez blok CATCH.
Aby uzyskać więcej informacji, zobacz Obsługa zakleszczeń.
Minimalizuj zakleszczenia
Chociaż zakleszczenia nie można całkowicie uniknąć, przestrzeganie pewnych konwencji kodowania może zminimalizować prawdopodobieństwo wygenerowania zakleszczenia. Zminimalizowanie zakleszczeń może zwiększyć przepływność transakcji i zmniejszyć obciążenie systemu, ponieważ mniej transakcji:
- Wycofano, cofając całą pracę wykonaną przez transakcję.
- Ponownie przesłano przez aplikacje, ponieważ zostały wycofane po zakleszczeniu.
Aby zminimalizować zakleszczenia:
- Uzyskuj dostęp do obiektów w tej samej kolejności.
- Unikaj interakcji użytkownika podczas transakcji.
- Zadbaj, aby transakcje były krótkie i należały do jednej partii.
- Unikaj wyższych poziomów izolacji, takich jak
REPEATABLE READiSERIALIZABLE, gdy nie są wymagane. - Użyj poziomu izolacji opartego na wersjach wierszy.
- Włącz opcję bazy danych
READ_COMMITTED_SNAPSHOT, aby korzystać z wersjonowania wierszy podczas transakcji z użyciem poziomu izolacjiREAD COMMITTED. - Użyj transakcji izolacji migawek.
- Włącz opcję bazy danych
- Użyj połączeń powiązanych.
Uzyskiwanie dostępu do obiektów w tej samej kolejności
Jeśli wszystkie współbieżne transakcje uzyskują dostęp do obiektów w tej samej kolejności, zakleszczenia są mniej prawdopodobne. Jeśli na przykład dwie współbieżne transakcje uzyskają blokadę w Supplier tabeli, a następnie w Part tabeli, jedna transakcja zostanie zablokowana w Supplier tabeli do momentu zakończenia drugiej transakcji. Po pierwszym zatwierdzeniu lub wycofaniu transakcji drugi będzie kontynuowany, a impas nie występuje. Korzystanie z procedur składowanych dla wszystkich modyfikacji danych umożliwia standaryzację kolejności uzyskiwania dostępu do obiektów.
Unikanie interakcji użytkownika w transakcjach
Unikaj transakcji obejmujących interakcję użytkownika, ponieważ szybkość uruchamiania partii bez interwencji użytkownika jest znacznie szybsza niż szybkość, z jaką użytkownik musi ręcznie reagować na zapytania, takie jak odpowiadanie na monit o parametr żądany przez aplikację. Obniża to przepływność systemu, ponieważ wszystkie blokady utrzymywane przez transakcję są zwalniane tylko, gdy transakcja zostanie zatwierdzona lub wycofana. Nawet jeśli zakleszczenie nie wystąpi, inne transakcje, które uzyskują dostęp do tych samych zasobów, są blokowane podczas oczekiwania na zakończenie transakcji.
Utrzymuj transakcje krótkie i w jednej partii
Zakleszczenie zwykle występuje, gdy kilka długotrwałych transakcji jest wykonywanych współbieżnie w tej samej bazie danych. Im dłuższa transakcja, tym dłużej są przechowywane blokady wyłączne lub aktualizacyjne, blokując inne działania i prowadząc do możliwych sytuacji zakleszczenia.
Zatrzymywanie transakcji w jednej grupie minimalizuje obroty sieciowe podczas transakcji, zmniejszając możliwe opóźnienia w jej zakończeniu z powodu przetwarzania przez klienta.
Unikaj wyższych poziomów izolacji
Ustal, czy transakcja może być uruchamiana na niższym poziomie izolacji. Użycie READ COMMITTED umożliwia transakcji odczytywanie danych wcześniej odczytanych (ale nie zmodyfikowanych) przez inną transakcję bez oczekiwania na zakończenie transakcji.
READ COMMITTED przechowuje udostępnione blokady przez krótszy czas niż wyższy poziom izolacji, taki jak SERIALIZABLE. Zmniejsza to rywalizację o blokadę.
Korzystanie z poziomu izolacji opartego na wersjonowaniu wierszy
Po ustawieniu READ_COMMITTED_SNAPSHOTONopcji bazy danych transakcja uruchomiona na READ COMMITTED poziomie izolacji używa przechowywania wersji wierszy, a nie blokad udostępnionych podczas operacji odczytu.
Wskazówka
Microsoft zaleca stosowanie poziomu izolacji opartego na wersjonowaniu wierszy za pomocą READ COMMITTED, chyba że aplikacja opiera się na zachowaniu blokującym poziomu izolacji opartego na blokadach za pomocą READ COMMITTED, dla wszystkich aplikacji.
Izolacja migawkowa również używa wersjonowania wierszy, które nie stosuje udostępnionych blokad podczas operacji odczytu. Aby transakcja mogła zostać uruchomiona w ramach izolacji migawki, należy ustawić opcję bazy danych ALLOW_SNAPSHOT_ISOLATIONON.
Użyj poziomów izolacji opartych na wersjach wierszy, aby zminimalizować zakleszczenia, które mogą wystąpić między operacjami odczytu i zapisu.
Korzystanie z powiązanych połączeń
Przy użyciu powiązanych połączeń co najmniej dwa połączenia otwarte przez tę samą aplikację mogą współpracować ze sobą. Wszelkie blokady nabyte przez połączenia pomocnicze są przechowywane tak, jakby zostały nabyte przez połączenie podstawowe i na odwrót. W związku z tym nie blokują się nawzajem.
Wywołaj zakleszczenie
Może zajść potrzeba wywołania zakleszczenia w celu nauki lub demonstracji.
Poniższy przykład działa w przykładowej bazie danych z domyślnym schematem i danymi, gdy AdventureWorksLT2019. Aby pobrać ten przykład, odwiedź stronę przykładowych baz danych AdventureWorks.
Aby zapoznać się z przykładem powodującym zakleszczenie po włączeniu zoptymalizowanego blokowania, zobacz Zoptymalizowane blokowanie i zakleszczenia.
Aby spowodować zakleszczenie, należy połączyć dwie sesje z bazą danych AdventureWorksLT2019. Te sesje nazywamy sesjami A i Sesją B. Te dwie sesje można utworzyć, tworząc dwa okna zapytań w programie SQL Server Management Studio (SSMS).
W sesji A uruchom następującą partię. Ten kod rozpoczyna jawną transakcję i wykonuje instrukcję, która aktualizuje tabelę SalesLT.Product . W tym celu transakcja uzyskuje blokadę aktualizacji (U) w kwalifikujących się wierszach w tabeli SalesLT.Product , które są następnie konwertowane na blokady wyłączne (X). Pozostawimy otwartą transakcję.
BEGIN TRANSACTION;
UPDATE SalesLT.Product
SET SellEndDate = SellEndDate + 1
WHERE Color = 'Red';
Teraz w sesji B uruchom następującą partię. Ten kod nie rozpoczyna jawnie transakcji. Zamiast tego działa w trybie automatycznego zatwierdzania transakcji. Ta instrukcja aktualizuje tabelę SalesLT.ProductDescription . Aktualizacja nakłada blokadę aktualizacji (U) na kwalifikujących się wierszach w tabeli SalesLT.ProductDescription. Zapytanie łączy się z innymi tabelami, w tym z tabelą SalesLT.Product .
UPDATE SalesLT.ProductDescription
SET Description = Description
FROM SalesLT.ProductDescription AS pd
INNER JOIN SalesLT.ProductModelProductDescription AS pmpd
ON pd.ProductDescriptionID = pmpd.ProductDescriptionID
INNER JOIN SalesLT.ProductModel AS pm
ON pmpd.ProductModelID = pm.ProductModelID
INNER JOIN SalesLT.Product AS p
ON pm.ProductModelID = p.ProductModelID
WHERE p.Color = 'Silver';
Aby ukończyć tę aktualizację, sesja B wymaga blokad udostępnionych (S) wierszy w tabeli SalesLT.Product, w tym wierszy zablokowanych przez sesję A. Sesja B jest zablokowana w dniu SalesLT.Product.
Wróć do sesji A. Uruchom następującą UPDATE instrukcję. Polecenie to jest wykonywane jako część wcześniej otwartej transakcji.
UPDATE SalesLT.ProductDescription
SET Description = Description
FROM SalesLT.ProductDescription AS pd
INNER JOIN SalesLT.ProductModelProductDescription AS pmpd
ON pd.ProductDescriptionID = pmpd.ProductDescriptionID
INNER JOIN SalesLT.ProductModel AS pm
ON pmpd.ProductModelID = pm.ProductModelID
INNER JOIN SalesLT.Product AS p
ON pm.ProductModelID = p.ProductModelID
WHERE p.Color = 'Red';
Drugie polecenie aktualizacji w sesji A jest blokowane przez sesję B na SalesLT.ProductDescription.
Sesja A i Sesja B wzajemnie się blokują. Żadna transakcja nie może kontynuować, ponieważ każda z nich potrzebuje zasobu zablokowanego przez drugą.
Po kilku sekundach monitor zakleszczenia identyfikuje, że transakcje w sesji A oraz sesji B blokują się nawzajem i że żadna z nich nie może poczynić postępów. Widzisz, jak występuje zakleszczenie, a sesja A jest wybrana jako ofiara zakleszczenia. Sesja B kończy się pomyślnie. W oknie zapytania sesji A zostanie wyświetlony komunikat o błędzie z tekstem podobnym do następującego przykładu:
Msg 1205, Level 13, State 51, Line 7
Transaction (Process ID 51) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Jeśli zakleszczenie nie zostanie zgłoszone, sprawdź, czy READ_COMMITTED_SNAPSHOT jest włączona w przykładowej bazie danych. Zakleszczenia mogą wystąpić w dowolnej konfiguracji bazy danych, ale ten przykład wymaga, aby READ_COMMITTED_SNAPSHOT była włączona.
Szczegóły zakleszczenia można wyświetlić w ring_buffer miejscu docelowym system_health sesji zdarzeń, która jest domyślnie włączona i aktywna w programach SQL Server i Azure SQL Managed Instance. Rozważ następujące zapytanie:
WITH cteDeadLocks ([Deadlock_XML])
AS (SELECT CAST (target_data AS XML) AS [Deadlock_XML]
FROM sys.dm_xe_sessions AS xs
INNER JOIN sys.dm_xe_session_targets AS xst
ON xs.[address] = xst.event_session_address
WHERE xs.[name] = 'system_health'
AND xst.target_name = 'ring_buffer')
SELECT x.Graph.query('(event/data/value/deadlock)[1]') AS Deadlock_XML,
x.Graph.value('(event/data/value/deadlock/process-list/process/@lastbatchstarted)[1]', 'datetime2(3)') AS when_occurred,
DB_Name(x.Graph.value('(event/data/value/deadlock/process-list/process/@currentdb)[1]', 'int')) AS DB --Current database of the first listed process
FROM (SELECT Graph.query('.') AS Graph
FROM cteDeadLocks AS c
CROSS APPLY c.[Deadlock_XML].nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS Deadlock_Report(Graph)) AS x
ORDER BY when_occurred DESC;
Kod XML można wyświetlić w kolumnie Deadlock_XML programu SSMS, wybierając komórkę, która wyświetla się jako hiperlink. Zapisz dane wyjściowe jako plik .xdl, zamknij go, a następnie ponownie otwórz w programie SSMS, aby uzyskać wizualny graf zakleszczenia .xdl. Graf zakleszczenia powinien wyglądać podobnie jak poniższa ilustracja.
Zoptymalizowane mechanizmy blokowania i zakleszczenia
W zoptymalizowanym blokowaniu blokady stron i wierszy nie są utrzymywane do końca transakcji. Są one zwalniane natychmiast po aktualizacji wiersza. Ponadto, jeśli READ_COMMITTED_SNAPSHOT jest włączona, blokady aktualizacji (U) nie są używane. W rezultacie ryzyko zakleszczenia zostaje zmniejszone.
Poprzedni przykład nie powoduje zakleszczenia, gdy zoptymalizowane blokowanie jest włączone, ponieważ opiera się na blokadach aktualizacji (U).
Poniższy przykład może służyć do spowodowania zakleszczenia w bazie danych z włączonym optymalizowanym blokowaniem.
Najpierw utwórz przykładową tabelę i dodaj dane.
CREATE TABLE t2
(
a INT PRIMARY KEY NOT NULL,
b INT NULL
);
INSERT INTO t2
VALUES (1, 10),
(2, 20),
(3, 30);
Następujące partie skryptów T-SQL, wykonywane kolejno w dwóch osobnych sesjach, tworzą zakleszczenie.
W sesji 1:
BEGIN TRANSACTION xactA;
UPDATE t2
SET b = b + 10
WHERE a = 1;
W sesji 2:
BEGIN TRANSACTION xactB;
UPDATE t2
SET b = b + 10
WHERE a = 2;
W sesji 1:
UPDATE t2
SET b = b + 100
WHERE a = 2;
W sesji 2:
UPDATE t2
SET b = b + 20
WHERE a = 1;
W takim przypadku każda sesja przechowuje wyłączną blokadę (X) na własnym zasobie identyfikatora transakcji (TID) i czeka na udostępnioną blokadę (S) na innym identyfikatorze TID, co powoduje zakleszczenie.
Poniższy skrócony i uproszczony raport syndromu zakleszczenia zawiera elementy i atrybuty specyficzne dla zoptymalizowanego blokowania. Pod każdym zasobem w raporcie <resource-list> zakleszczenia, każdy element <xactlock> raportuje bazowe zasoby i informacje o blokadzie TID każdego członka zakleszczenia.
<deadlock>
<victim-list>
<victimProcess id="process12994344c58" />
</victim-list>
<process-list>
<process id="process12994344c58" taskpriority="0" logused="272" waitresource="XACT: 23:2476:0 KEY: 23:72057594049593344 (8194443284a0)" waittime="447" ownerId="3234906" transactionname="xactA" lasttranstarted="2025-10-08T21:36:34.063" XDES="0x12984ba0480" lockMode="S" schedulerid="2" kpid="204928" status="suspended" spid="95" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2025-10-08T21:36:40.857" lastbatchcompleted="2025-10-08T21:36:34.063" lastattention="2025-10-08T21:36:11.340" clientapp="Microsoft SQL Server Management Studio - Query" hostname="WS1" hostpid="23380" loginname="user1" isolationlevel="read committed (2)" xactid="3234906" currentdb="23" currentdbname="AdventureWorksLT" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
<inputbuf>
UPDATE t2
SET b = b + 20
WHERE a = 1;
</inputbuf>
</process>
<process id="process1299c969828" taskpriority="0" logused="272" waitresource="XACT: 23:2477:0 KEY: 23:72057594049593344 (61a06abd401c)" waittime="3083" ownerId="3234886" transactionname="xactB" lasttranstarted="2025-10-08T21:36:30.303" XDES="0x12995c84480" lockMode="S" schedulerid="2" kpid="63348" status="suspended" spid="88" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2025-10-08T21:36:38.223" lastbatchcompleted="2025-10-08T21:36:30.303" lastattention="1900-01-01T00:00:00.303" clientapp="Microsoft SQL Server Management Studio - Query" hostname="WS1" hostpid="23380" loginname="user1" isolationlevel="read committed (2)" xactid="3234886" currentdb="23" currentdbname="AdventureWorksLT" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
<inputbuf>
UPDATE t2
SET b = b + 100
WHERE a = 2;
</inputbuf>
</process>
</process-list>
<resource-list>
<xactlock xdesIdLow="2476" xdesIdHigh="0" dbid="23" id="lock1299fa06c00" mode="X">
<UnderlyingResource>
<keylock hobtid="72057594049593344" dbid="23" objectname="e6fc405e-1ee8-49df-a2b3-54ee0151d851.dbo.t2" indexname="PK__t2__3BD0198ED3CBA65E" />
</UnderlyingResource>
<owner-list>
<owner id="process1299c969828" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process12994344c58" mode="S" requestType="wait" />
</waiter-list>
</xactlock>
<xactlock xdesIdLow="2477" xdesIdHigh="0" dbid="23" id="lock129940b2380" mode="X">
<UnderlyingResource>
<keylock hobtid="72057594049593344" dbid="23" objectname="e6fc405e-1ee8-49df-a2b3-54ee0151d851.dbo.t2" indexname="PK__t2__3BD0198ED3CBA65E" />
</UnderlyingResource>
<owner-list>
<owner id="process12994344c58" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process1299c969828" mode="S" requestType="wait" />
</waiter-list>
</xactlock>
</resource-list>
</deadlock>
Treści powiązane
- Omówienie zdarzeń rozszerzonych
- sys.dm_tran_locks (Transact-SQL)
- Klasa zdarzeń „Deadlock Graph”
- Zakleszczenia z poziomem izolacji powtarzalności odczytu
- Zablokuj:Klasa zdarzeń łańcucha zakleszczeń
- Lock:Klasa zdarzeń zakleszczenia
- SET DEADLOCK_PRIORITY (Transact-SQL)
- Analizowanie i zapobieganie zakleszczeniom w usłudze Azure SQL Database i bazie danych SQL w Fabric
- Otwórz, wyświetl i wydrukuj plik zakleszczenia w programie SQL Server Management Studio (SSMS)