Udostępnij za pośrednictwem


Analizowanie i zapobieganie zakleszczeniom w usłudze Azure SQL Database i bazie danych SQL Fabric

Dotyczy:Baza danych SQL Usługi Azure SQL Databasew sieci szkieletowej

W tym artykule przedstawiono sposób identyfikowania zakleszczeń, używania wykresów zakleszczenia i magazynu zapytań do identyfikowania zapytań w impasie oraz planowania i testowania zmian, aby zapobiec ponownemu zakleszczeniu. Ten artykuł dotyczy bazy danych SQL Azure SQL Database i fabric SQL Database, która udostępnia wiele funkcji usługi Azure SQL Database.

Ten artykuł koncentruje się na identyfikowaniu i analizowaniu zakleszczeń ze względu na rywalizację o blokadę. Dowiedz się więcej o innych typach zakleszczeń w zasobach, które mogą zakleszczeć.

Jak występują zakleszczenia

Każda nowa baza danych w usłudze Azure SQL Database ma domyślnie włączone ustawienie bazy danych izolacji odczytu z zatwierdzonymi migawkami (RCSI). Blokowanie między sesjami odczytu danych i sesji zapisywania danych jest zminimalizowane w obszarze RCSI, co używa przechowywania wersji wierszy w celu zwiększenia współbieżności. Jednak blokowanie i zakleszczenia mogą nadal występować w bazach danych w usłudze Azure SQL Database, ponieważ:

  • Zapytania modyfikujące dane mogą blokować się nawzajem.

  • Zapytania mogą być uruchamiane na poziomach izolacji, które zwiększają blokowanie. Poziomy izolacji można określić za pomocą metod biblioteki klienta, wskazówek dotyczących zapytańlub USTAWIĆ POZIOM IZOLACJI TRANSAKCJI w języku Transact-SQL.

  • RCSI może być wyłączona, co powoduje, że baza danych używa udostępnionych blokad (S) w celu ochrony instrukcji SELECT uruchamianych na poziomie izolacji zatwierdzonej do odczytu. Może to zwiększyć blokowanie i zakleszczenia.

Przykład zakleszczenia

Zakleszczenie występuje, gdy co najmniej dwa zadania trwale blokują się nawzajem, ponieważ każde zadanie ma blokadę zasobu, który próbuje zablokować drugie zadanie. Zakleszczenie jest również nazywane cykliczną zależnością: w przypadku zakleszczenia dwóch zadań transakcja A ma zależność od transakcji B, a transakcja B zamyka koło, mając zależność od transakcji A.

Na przykład:

  1. Sesja A rozpoczyna transakcję jawną i uruchamia instrukcję aktualizacji, która uzyskuje blokadę aktualizacji (U) w jednym wierszu w tabeliSalesLT.Product, który jest konwertowany na blokadę wyłączną (X).

  2. Sesja B uruchamia instrukcję aktualizacji, która modyfikuje tabelę SalesLT.ProductDescription . Instrukcja update łączy się z tabelą, SalesLT.Product aby znaleźć poprawne wiersze do zaktualizowania.

    • Sesja B uzyskuje blokadę aktualizacji (U) na 72 wierszach w SalesLT.ProductDescription tabeli.

    • Sesja B wymaga udostępnionej blokady wierszy w tabeli SalesLT.Product, w tym wiersza zablokowanego przez sesję A. Sesja B jest zablokowana w dniu SalesLT.Product.

  3. Sesja A kontynuuje transakcję, a teraz uruchamia aktualizację względem SalesLT.ProductDescription tabeli. Sesja A jest blokowana przez sesję B w dniu SalesLT.ProductDescription.

Diagram przedstawiający dwie sesje w impasie. Każda sesja jest właścicielem zasobu, którego potrzebuje inny proces, aby kontynuować.

Wszystkie transakcje w impasie czekają na czas nieokreślony, chyba że jedna z uczestniczących transakcji zostanie wycofana, na przykład z powodu zakończenia sesji.

Monitor zablokowania aparatu bazy danych okresowo sprawdza pod kątem zadań, które są blokowane. Jeśli monitor zakleszczenia wykryje cykliczną zależność, wybiera jedno z zadań jako ofiarę i kończy transakcję z błędem 1205: Transaction (Process ID <N>) was deadlocked on lock resources with another process and is chosen as the deadlock victim. Rerun the transaction. Przerwanie zakleszczenia w ten sposób umożliwia wykonywanie innych zadań lub zadań w impasie w celu ukończenia transakcji.

Uwaga

Dowiedz się więcej o kryteriach wybierania ofiary zakleszczenia w sekcji lista procesów zakleszczenia w tym artykule.

Diagram impasu między dwiema sesjami. Jedna sesja zostaje wybrana jako ofiara impasu.

Aplikacja z transakcją wybraną jako ofiara zakleszczenia powinna ponowić próbę transakcji, która zwykle kończy się po zakończeniu drugiej transakcji lub transakcji zaangażowanych w zakleszczenie.

Najlepszym rozwiązaniem jest wprowadzenie krótkiego, losowego opóźnienia przed ponowną próbą, aby uniknąć ponownego napotkania tego samego impasu. Dowiedz się więcej na temat projektowania logiki ponawiania prób dla błędów przejściowych.

Domyślny poziom izolacji w usłudze Azure SQL Database

Nowe bazy danych w usłudze Azure SQL Database domyślnie włączają migawkę zatwierdzoną do odczytu (RCSI). RCSI zmienia zachowanie poziomu izolacji zatwierdzonej do odczytu , aby wykorzystywać wersjonowanie wierszy i zapewniać spójność na poziomie instrukcji bez użycia współdzielonych blokad (S) dla instrukcji SELECT.

Z włączoną funkcją RCSI:

  • Instrukcje odczytujące dane nie blokują instrukcji modyfikujących dane.
  • Instrukcje modyfikujące dane nie blokują instrukcji odczytu danych.

Poziom izolacji migawek jest również domyślnie włączony dla nowych baz danych w usłudze Azure SQL Database. Izolacja migawki to dodatkowy poziom izolacji oparty na wierszach, który zapewnia spójność na poziomie transakcji dla danych i który używa wersji wierszy do wybierania wierszy do aktualizacji. Aby użyć izolacji migawki, zapytania lub połączenia muszą jawnie ustawić poziom izolacji transakcji na SNAPSHOTwartość . Można to zrobić tylko wtedy, gdy dla bazy danych jest włączona izolacja migawki.

Możesz określić, czy izolacja RCSI i/lub migawki jest włączona w języku Transact-SQL. Połącz się z bazą danych w usłudze Azure SQL Database i uruchom następujące zapytanie:

SELECT name,
       is_read_committed_snapshot_on,
       snapshot_isolation_state_desc
FROM sys.databases
WHERE name = DB_NAME();
GO

Jeśli opcja RCSI jest włączona, kolumna is_read_committed_snapshot_on zwraca wartość 1. Jeśli izolacja migawki jest włączona, kolumna snapshot_isolation_state_desc zwraca wartość ON.

Jeśli RCSI jest wyłączona dla bazy danych w usłudze Azure SQL Database, sprawdź, dlaczego funkcja RCSI została wyłączona przed ponownym włączeniem. Kod aplikacji może oczekiwać, że zapytania odczytujące dane będą blokowane przez zapytania zapisujące dane, co powoduje nieprawidłowe wyniki z warunków wyścigu po włączeniu funkcji RCSI.

Interpretuj zdarzenia zakleszczenia

Zdarzenie zakleszczenia jest emitowane po wykryciu zakleszczenia przez menedżera zakleszczenia w usłudze Azure SQL Database i wybraniu transakcji jako ofiary. Innymi słowy, jeśli skonfigurujesz alerty dotyczące zakleszczeń, powiadomienie zostanie wysłane po rozwiązaniu pojedynczego zakleszczenia. Nie ma żadnych działań użytkownika, które należy podjąć w przypadku tego zakleszczenia. Aplikacje powinny być zapisywane w celu uwzględnienia logiki ponawiania prób, aby były one automatycznie kontynuowane po otrzymaniu błędu 1205: Transaction (Process ID <N>) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Warto jednak skonfigurować alerty, ponieważ zakleszczenia mogą się powtarzać. Alerty zakleszczenia umożliwiają sprawdzenie, czy w bazie danych występuje wzorzec powtarzających się zakleszczeń, w którym przypadku można podjąć działania, aby zapobiec ponownemu zakleszczeniu. Dowiedz się więcej na temat alertów w sekcji Monitorowanie i alerty dotyczące zakleszczeń w tym artykule.

Najważniejsze metody zapobiegania zakleszczeniom

Najniższym podejściem do ryzyka zapobiegania zakleszczeniom z reoccurringu jest zazwyczaj dostrajanie indeksów nieklastrowanych w celu optymalizacji zapytań związanych z zakleszczeniem.

  • Ryzyko jest niskie w przypadku tego podejścia, ponieważ dostrajanie indeksów nieklastrowanych nie wymaga zmian w kodzie zapytania, co zmniejsza ryzyko błędu użytkownika podczas ponownego zapisywania języka Transact-SQL, co powoduje zwrócenie użytkownikowi nieprawidłowych danych.

  • Skuteczne dostrajanie indeksu nieklastrowanego pomaga wyszukiwać dane w celu bardziej wydajnego odczytywania i modyfikowania. Dzięki zmniejszeniu ilości danych, do których musi uzyskać dostęp zapytanie, prawdopodobieństwo blokowania jest zmniejszane i często można zapobiec zakleszczeniom.

W niektórych przypadkach tworzenie lub dostrajanie indeksu klastrowanego może zmniejszyć blokowanie i zakleszczenia. Ponieważ indeks klastrowany jest uwzględniany we wszystkich nieklastrowanych definicjach indeksu, tworzenie lub modyfikowanie indeksu klastrowanego może być operacją intensywnie korzystającą z operacji we/wy i czasochłonną operacją na większych tabelach z istniejącymi indeksami nieklastrowanym. Dowiedz się więcej na temat wytycznych dotyczących projektowania indeksu klastrowanego.

Gdy dostrajanie indeksu nie powiedzie się w zapobieganiu zakleszczeniom, dostępne są inne metody:

  • Jeśli zakleszczenie występuje tylko wtedy, gdy określony plan zostanie wybrany dla jednego z zapytań zaangażowanych w zakleszczenie, wymuszanie planu zapytania z magazynem zapytań może uniemożliwić ponowne zakleszczenie.

  • Ponowne zapisywanie języka Transact-SQL dla co najmniej jednej transakcji zaangażowanej w zakleszczenie może również pomóc w zapobieganiu zakleszczeniom. Podzielenie jawnych transakcji na mniejsze transakcje wymaga starannego kodowania i testowania, aby zapewnić ważność danych podczas współbieżnych modyfikacji.

Dowiedz się więcej o każdym z tych podejść w sekcji Zapobieganie zakleszczeniom w tym artykule.

Monitorowanie zakleszczeń i zgłaszanie alertów

W tym artykule użyjemy przykładowej bazy danych AdventureWorksLT do skonfigurowania alertów dotyczących zakleszczeń, spowodowania przykładowego zakleszczenia, przeanalizowania wykresu zakleszczenia dla przykładowego zakleszczenia i przetestowania zmian, aby zapobiec ponownemu zakleszczeniu.

W tym artykule używamy klienta programu SQL Server Management Studio (SSMS), ponieważ zawiera on funkcje wyświetlania grafów zakleszczenia w trybie interaktywnym. Możesz użyć innych klientów, takich jak Azure Data Studio, aby postępować zgodnie z przykładami, ale możesz wyświetlać wykresy zakleszczenia tylko jako XML.

Tworzenie bazy danych AdventureWorksLT

Aby postępować zgodnie z przykładami, utwórz nową bazę danych w usłudze Azure SQL Database i wybierz pozycję Przykładowe dane jako źródło danych.

Aby uzyskać szczegółowe instrukcje dotyczące tworzenia za AdventureWorksLT pomocą witryny Azure Portal, interfejsu wiersza polecenia platformy Azure lub programu PowerShell, wybierz wybrane podejście w przewodniku Szybki start: Tworzenie pojedynczej bazy danych usługi Azure SQL Database.

Konfigurowanie alertów zakleszczenia w witrynie Azure Portal

Aby skonfigurować alerty dotyczące zdarzeń zakleszczenia, wykonaj kroki opisane w artykule Tworzenie alertów dla usług Azure SQL Database i Azure Synapse Analytics przy użyciu witryny Azure Portal.

Wybierz pozycję Zakleszczenia jako nazwę sygnału alertu. Skonfiguruj grupę akcji, aby powiadomić Cię przy użyciu wybranej metody, takiej jak typ akcji Email/SMS/Push/Voice.

Zbieranie wykresów zakleszczenia w usłudze Azure SQL Database przy użyciu zdarzeń rozszerzonych

Wykresy zakleszczenia są bogatym źródłem informacji dotyczących procesów i blokad związanych z impasem. Aby zebrać wykresy zakleszczenia z zdarzeniami rozszerzonymi (XEvents) w usłudze Azure SQL Database, przechwyć sqlserver.database_xml_deadlock_report zdarzenie.

Wykresy zakleszczenia można zbierać z elementami XEvents przy użyciu docelowego buforu pierścieniowego lub docelowego pliku zdarzeń. Zagadnienia dotyczące wybierania odpowiedniego typu docelowego zostały podsumowane w poniższej tabeli:

Metoda Świadczenia Kwestie wymagające rozważenia Scenariusze użycia
Element docelowy buforu pierścieniowego — Prosta konfiguracja tylko przy użyciu Transact-SQL. — Dane zdarzenia są usuwane, gdy sesja XEvents zostanie zatrzymana z jakiegokolwiek powodu, na przykład w przypadku przełączania bazy danych w tryb offline lub awaryjnego przełączenia bazy danych.

— Zasoby bazy danych są używane do obsługi danych w buforze pierścieniowym i wykonywania zapytań dotyczących danych sesji.
— Zbieranie przykładowych danych śledzenia na potrzeby testowania i uczenia.

— Utwórz dla potrzeb krótkoterminowych, jeśli nie można natychmiast skonfigurować sesji przy użyciu obiektu docelowego pliku zdarzeń.

— Użyj jako miejsca docelowego dla danych śledzenia, gdy masz skonfigurowany zautomatyzowany proces zapisywania danych śledzenia w tabeli.
Miejsce docelowe pliku zdarzenia — Przechowuje dane zdarzeń w obiekcie blob w usłudze Azure Storage, dzięki czemu dane są dostępne nawet po zatrzymaniu sesji.

— Pliki zdarzeń można pobrać z witryny Azure Portal lub Eksploratora usługi Azure Storage i analizować lokalnie, co nie wymaga używania zasobów bazy danych do wykonywania zapytań dotyczących danych sesji.
— Konfiguracja jest bardziej złożona i wymaga konfiguracji kontenera usługi Azure Storage i poświadczeń o zakresie bazy danych. — Do ogólnego użytku, gdy chcesz, aby dane zdarzeń były utrwalane nawet po zakończeniu sesji zdarzeń.

— Chcesz uruchomić ślad, który generuje większe ilości danych zdarzeń niż chcesz zachować w pamięci.

Wybierz typ docelowy, którego chcesz użyć:

Cel buforu pierścieniowego jest wygodny i łatwy do skonfigurowania, ale ma ograniczoną pojemność, co może spowodować utratę starszych zdarzeń. Bufor pierścieniowy nie zapisuje zdarzeń w pamięci, a docelowy bufor pierścieniowy jest czyszczony po zatrzymaniu sesji XEvents. Oznacza to, że wszystkie zebrane elementy XEvent nie są dostępne w przypadku ponownego uruchomienia aparatu bazy danych ze względu na dowolny powód, taki jak przełączenie awaryjne. Cel buforu pierścienia najlepiej nadaje się do nauki i krótkoterminowych potrzeb, jeśli nie masz możliwości natychmiastowego skonfigurowania sesji XEvents na pliku docelowym zdarzeń.

Ten przykładowy kod tworzy sesję XEvents, która przechwytuje wykresy zakleszczenia w pamięci przy użyciu docelowego buforu pierścienia. Maksymalna dozwolona pamięć dla docelowego buforu pierścieniowego wynosi 4 MB, a sesja jest uruchamiana automatycznie, gdy baza danych jest w trybie online, na przykład po przejściu w tryb failover.

Aby utworzyć, a następnie uruchomić sesję XEvents dla sqlserver.database_xml_deadlock_report zdarzenia, które zapisuje w docelowym buforze pierścienia, połącz się z bazą danych i uruchom następujący kod Transact-SQL:

CREATE EVENT SESSION [deadlocks] ON DATABASE
ADD EVENT sqlserver.database_xml_deadlock_report
ADD TARGET package0.ring_buffer
WITH
(
    STARTUP_STATE = ON,
    MAX_MEMORY = 4 MB
);
GO

ALTER EVENT SESSION [deadlocks] ON DATABASE
STATE = START;
GO

Przyczyna zakleszczenia w AdventureWorksLT

Uwaga

Ten przykład działa w bazie danych AdventureWorksLT z domyślnym schematem i danymi po włączeniu funkcji RCSI. Aby uzyskać instrukcje dotyczące tworzenia bazy danych, zobacz Tworzenie bazy danych AdventureWorksLT.

Aby spowodować zakleszczenie, należy połączyć dwie sesje z bazą danych AdventureWorksLT. Te sesje określamy jako Sesja A i Sesja B.

W sesji A uruchom następujące polecenie Języka Transact-SQL. Ten kod rozpoczyna jawną transakcję i uruchamia pojedynczą instrukcję, która aktualizuje tabelęSalesLT.Product. W tym celu transakcja uzyskuje blokadęSalesLT.Productwyłączną (X). Pozostawimy otwartą transakcję.

BEGIN TRANSACTION;

UPDATE SalesLT.Product
SET SellEndDate = SellEndDate + 1
WHERE Color = 'Red';

Teraz w sesji B uruchom następujący kod Transact-SQL. Ten kod nie rozpoczyna jawnie transakcji. Zamiast tego działa w trybie automatycznej transakcji. Ta instrukcja aktualizuje tabelę SalesLT.ProductDescription . Aktualizacja zakłada aktualizacyjną blokadę (U) na 72 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 współużytkowanej blokady (S) na wiersze w tabeli SalesLT.Product, w tym wiersza zablokowanego przez sesję A. sesja B jest zablokowana na SalesLT.Product.

Wróć do sesji A. Uruchom następującą instrukcję języka Transact-SQL. Spowoduje to uruchomienie drugiej instrukcji UPDATE w ramach 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';

Druga instrukcja aktualizacji w sesji A jest blokowana 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. Powinna pojawić się impas, a sesja A wybrana jako ofiara zakleszczenia. Komunikat o błędzie jest wyświetlany w sesji A z tekstem podobnym do następującego:

Msg 1205, Level 13, State 51, Line 7
Transaction (Process ID 91) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Sesja B kończy się pomyślnie.

W przypadku skonfigurowania alertów zakleszczenia w witrynie Azure Portal powinno zostać wyświetlone powiadomienie wkrótce po wystąpieniu zakleszczenia.

Wyświetlanie wykresów zakleszczenia z sesji XEvents

Jeśli skonfigurujesz sesję XEvents, aby zbierać zakleszczenia i zakleszczenie wystąpi po rozpoczęciu sesji, możesz wyświetlić interaktywne graficzne przedstawienie grafu zakleszczenia oraz XML tego grafu.

Dostępne są różne metody uzyskiwania informacji o zakleszczeniach dla obiektów docelowych buforu pierścienia i obiektów docelowych plików zdarzeń. Wybierz element docelowy używany dla sesji XEvents:

Jeśli skonfigurujesz sesję XEvents zapisu w buforze pierścienia, możesz wykonywać zapytania dotyczące zakleszczenia przy użyciu następującego języka Transact-SQL. Przed uruchomieniem zapytania zastąp wartość @tracename nazwą sesji XEvents.

DECLARE @tracename AS sysname = N'deadlocks';

WITH ring_buffer
AS (SELECT CAST (target_data AS XML) AS rb
    FROM sys.dm_xe_database_sessions AS s
         INNER JOIN sys.dm_xe_database_session_targets AS t
             ON CAST (t.event_session_address AS BINARY (8)) = CAST (s.address AS BINARY (8))
    WHERE s.name = @tracename
          AND t.target_name = N'ring_buffer'),
 dx
AS (SELECT dxdr.evtdata.query('.') AS deadlock_xml_deadlock_report
    FROM ring_buffer
CROSS APPLY rb.nodes('/RingBufferTarget/event[@name=''database_xml_deadlock_report'']') AS dxdr(evtdata))
SELECT d.query('/event/data[@name=''deadlock_cycle_id'']/value').value('(/value)[1]', 'int') AS [deadlock_cycle_id],
       d.value('(/event/@timestamp)[1]', 'DateTime2') AS [deadlock_timestamp],
       d.query('/event/data[@name=''database_name'']/value').value('(/value)[1]', 'nvarchar(256)') AS [database_name],
       d.query('/event/data[@name=''xml_report'']/value/deadlock') AS deadlock_xml,
       LTRIM(RTRIM(REPLACE(REPLACE(d.value('.', 'nvarchar(2000)'), CHAR(10), ' '), CHAR(13), ' '))) AS query_text
FROM dx
CROSS APPLY deadlock_xml_deadlock_report.nodes('(/event/data/value/deadlock/process-list/process/inputbuf)') AS ib(d)
ORDER BY [deadlock_timestamp] DESC;
GO

Wyświetlanie i zapisywanie grafu zakleszczenia w formacie XML

Wyświetlanie wykresu zakleszczenia w formacie XML umożliwia skopiowanie inputbuffer instrukcji języka Transact-SQL zaangażowanych w zakleszczenie. Możesz także analizować zatory w formacie tekstowym.

Jeśli użyto zapytania Transact-SQL w celu zwrócenia informacji o grafie zakleszczenia, aby wyświetlić kod XML grafu zakleszczenia, wybierz wartość w deadlock_xml kolumnie z dowolnego wiersza, aby otworzyć kod XML grafu zakleszczenia w nowym oknie w programie SSMS.

Kod XML dla tego przykładowego grafu zakleszczenia to:

<deadlock>
  <victim-list>
    <victimProcess id="process24756e75088" />
  </victim-list>
  <process-list>
    <process id="process24756e75088" taskpriority="0" logused="6528" waitresource="KEY: 8:72057594045202432 (98ec012aa510)" waittime="192" ownerId="1011123" transactionname="user_transaction" lasttranstarted="2022-03-08T15:44:43.490" XDES="0x2475c980428" lockMode="U" schedulerid="3" kpid="30192" status="suspended" spid="89" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-03-08T15:44:49.250" lastbatchcompleted="2022-03-08T15:44:49.210" lastattention="1900-01-01T00:00:00.210" clientapp="Microsoft SQL Server Management Studio - Query" hostname="LAPTOP-CHRISQ" hostpid="16716" loginname="chrisqpublic" isolationlevel="read committed (2)" xactid="1011123" currentdb="8" currentdbname="AdventureWorksLT" lockTimeout="4294967295" clientoption1="671096864" clientoption2="128056">
      <executionStack>
        <frame procname="unknown" queryhash="0xef52b103e8b9b8ca" queryplanhash="0x02b0f58d7730f798" line="1" stmtstart="2" stmtend="792" sqlhandle="0x02000000c58b8f1e24e8f104a930776e21254b1771f92a520000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
      <inputbuf>
    UPDATE SalesLT.ProductDescription SET Description = Description
        FROM SalesLT.ProductDescription as pd
        JOIN SalesLT.ProductModelProductDescription as pmpd on
            pd.ProductDescriptionID = pmpd.ProductDescriptionID
        JOIN SalesLT.ProductModel as pm on
            pmpd.ProductModelID = pm.ProductModelID
        JOIN SalesLT.Product as p on
            pm.ProductModelID=p.ProductModelID
        WHERE p.Color = 'Red'   </inputbuf>
    </process>
    <process id="process2476d07d088" taskpriority="0" logused="11360" waitresource="KEY: 8:72057594045267968 (39e18040972e)" waittime="2641" ownerId="1013536" transactionname="UPDATE" lasttranstarted="2022-03-08T15:44:46.807" XDES="0x2475ca80428" lockMode="S" schedulerid="2" kpid="94040" status="suspended" spid="95" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-03-08T15:44:46.807" lastbatchcompleted="2022-03-08T15:44:46.760" lastattention="1900-01-01T00:00:00.760" clientapp="Microsoft SQL Server Management Studio - Query" hostname="LAPTOP-CHRISQ" hostpid="16716" loginname="chrisqpublic" isolationlevel="read committed (2)" xactid="1013536" currentdb="8" currentdbname="AdventureWorksLT" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
      <executionStack>
        <frame procname="unknown" queryhash="0xef52b103e8b9b8ca" queryplanhash="0x02b0f58d7730f798" line="1" stmtstart="2" stmtend="798" sqlhandle="0x020000002c85bb06327c0852c0be840fc1e30efce2b7c8090000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
      <inputbuf>
    UPDATE SalesLT.ProductDescription SET Description = Description
        FROM SalesLT.ProductDescription as pd
        JOIN SalesLT.ProductModelProductDescription as pmpd on
            pd.ProductDescriptionID = pmpd.ProductDescriptionID
        JOIN SalesLT.ProductModel as pm on
            pmpd.ProductModelID = pm.ProductModelID
        JOIN SalesLT.Product as p on
            pm.ProductModelID=p.ProductModelID
        WHERE p.Color = 'Silver';   </inputbuf>
    </process>
  </process-list>
  <resource-list>
    <keylock hobtid="72057594045202432" dbid="8" objectname="9e011567-2446-4213-9617-bad2624ccc30.SalesLT.ProductDescription" indexname="PK_ProductDescription_ProductDescriptionID" id="lock2474df12080" mode="U" associatedObjectId="72057594045202432">
      <owner-list>
        <owner id="process2476d07d088" mode="U" />
      </owner-list>
      <waiter-list>
        <waiter id="process24756e75088" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
    <keylock hobtid="72057594045267968" dbid="8" objectname="9e011567-2446-4213-9617-bad2624ccc30.SalesLT.Product" indexname="PK_Product_ProductID" id="lock2474b588580" mode="X" associatedObjectId="72057594045267968">
      <owner-list>
        <owner id="process24756e75088" mode="X" />
      </owner-list>
      <waiter-list>
        <waiter id="process2476d07d088" mode="S" requestType="wait" />
      </waiter-list>
    </keylock>
  </resource-list>
</deadlock>

Aby zapisać graf zakleszczenia jako plik XML:

  1. Wybierz pozycję Plik i Zapisz jako....
  2. Pozostaw wartość Zapisz jako typ jako domyślną wartość Pliki XML (*.xml)
  3. Ustaw nazwę pliku na wybraną nazwę.
  4. Wybierz pozycję Zapisz.

Zapisywanie grafu zakleszczenia jako pliku XDL, który może być wyświetlany interaktywnie w programie SSMS

Wyświetlenie interaktywnej reprezentacji grafu zakleszczenia może być przydatne, aby uzyskać szybki przegląd procesów i zasobów związanych z impasem oraz szybkie identyfikowanie ofiary zakleszczenia.

Aby zapisać wykres zakleszczenia jako plik, który może być wyświetlany graficznie przez program SSMS:

  1. Wybierz wartość w kolumnie deadlock_xml z dowolnego wiersza, aby otworzyć kod XML grafu zakleszczenia w nowym oknie w programie SSMS.

  2. Wybierz pozycję Plik i Zapisz jako....

  3. Ustaw pozycję Zapisz jako typ na Wszystkie pliki.

  4. Ustaw nazwę pliku na wybraną nazwę, a rozszerzenie ma wartość .xdl.

  5. Wybierz pozycję Zapisz.

    Zrzut ekranu w programie SSMS przedstawiający zapisanie pliku XML grafu zakleszczenia jako plik z rozszerzeniem xsd.

  6. Zamknij plik, wybierając ikonę X na karcie w górnej części okna lub wybierając pozycję Plik, a następnie zamknij.

  7. Otwórz ponownie plik w programie SSMS, wybierając pozycję Plik, a następnie otwórz, a następnie pozycję Plik. Wybierz zapisany plik z .xdl rozszerzeniem .

    Wykres zakleszczenia jest teraz wyświetlany w programie SSMS z wizualną reprezentacją procesów i zasobów zaangażowanych w zakleszczenie.

    Zrzut ekranu przedstawiający plik XDL otwarty w programie SSMS. Wykres zakleszczenia jest wyświetlany graficznie z procesami wskazywanymi przez owalne i zablokowane zasoby jako prostokąty.

Analizowanie zakleszczenia dla usługi Azure SQL Database

Wykres zakleszczenia zwykle ma trzy węzły:

  • Lista ofiar. Identyfikator procesu ofiary zakleszczenia.

  • Lista procesów. Informacje na temat wszystkich procesów związanych z zakleszczeniem. Wykresy zakleszczenia używają terminu "proces" do reprezentowania sesji uruchamianej transakcji.

  • Lista zasobów. Informacje o zasobach powiązanych z zakleszczeniem.

Podczas analizowania zakleszczenia warto krok po kroku przeanalizować te węzły.

Lista ofiar zakleszczenia

Lista ofiar zakleszczenia pokazuje proces, który został wybrany jako ofiara impasu. W wizualnej reprezentacji grafu zakleszczenia procesy są reprezentowane przez owalny. Proces ofiary impasu ma "X" narysowany na owalnym.

Zrzut ekranu przedstawiający wizualizację zakleszczenia. Owalu reprezentującego proces wybrany jako ofiara ma naciągnięty znak X.

W widoku XML grafuvictim-list zakleszczenia węzeł podaje identyfikator procesu, który był ofiarą zakleszczenia.

W naszym przykładzie zakleszczenia identyfikatorem procesu ofiary jest process24756e75088. Możemy użyć tego identyfikatora podczas badania węzłów listy procesów i listy zasobów, aby dowiedzieć się więcej o procesie ofiary i zasobach, które zablokowała lub zażądała blokady.

Lista procesów zakleszczenia

Lista procesów zakleszczenia jest bogatym źródłem informacji o transakcjach związanych z impasem.

Graficzna reprezentacja grafu zakleszczenia przedstawia tylko podzbiór informacji zawartych w grafie zakleszczenia XML. Owalny na wykresie zakleszczenia reprezentują proces i pokazują informacje, w tym:

  • Identyfikator sesji, znany również jako SPID.

  • Priorytet zakleszczenia sesji. Jeśli dwie sesje mają różne priorytety zakleszczenia, sesja o niższym priorytecie zostanie wybrana jako ofiara zakleszczenia. W tym przykładzie obie sesje mają ten sam priorytet zakleszczenia.

  • Ilość dziennika transakcji używanego przez sesję w bajtach. Jeśli obie sesje mają taki sam priorytet zakleszczenia, monitor zakleszczenia wybiera sesję, która jest tańsza, aby wycofać się jako ofiara zakleszczenia. Koszt jest określany przez porównanie liczby bajtów dziennika zapisanych w tym punkcie w każdej transakcji.

    W naszym przykładzie zakleszczenia, węzeł session_id 89 użył mniejszej ilości dziennika transakcji i został wybrany jako ofiara zakleszczenia.

Ponadto można wyświetlić bufor wejściowy dla ostatniej instrukcji uruchomionej w każdej sesji przed zakleszczeniem, umieszczając wskaźnik myszy nad każdym procesem. Bufor wejściowy jest wyświetlany w etykietce narzędzia.

Zrzut ekranu przedstawiający wykres zakleszczenia wyświetlany wizualnie w programie SSMS. Dwa owale reprezentują procesy. Bufor wejściowy dla jednego procesu jest pokazany.

Dodatkowe informacje są dostępne dla procesów w widoku XML grafu zakleszczenia, w tym:

  • Identyfikowanie informacji dotyczących sesji, takich jak nazwa klienta, nazwa hosta i nazwa logowania.

  • Skrót planu zapytania dla ostatniej instrukcji, która została uruchomiona przez każdą sesję przed wystąpieniem zakleszczenia. Skrót planu zapytania jest przydatny do pobierania dodatkowych informacji o zapytaniu z magazynu zapytań.

W naszym przykładzie zakleszczenia:

  • Widzimy, że obie sesje zostały uruchomione przy użyciu klienta SSMS w logowania chrisqpublic.

  • Skrót planu zapytania związany z ostatnią instrukcją uruchomioną przed zakleszczeniem, w której uczestniczyła nasza ofiara zakleszczenia, to 0x02b0f58d7730f798. Tekst tej instrukcji można zobaczyć w buforze wejściowym.

  • Skrót planu zapytania z ostatniego polecenia uruchomionego przez inną sesję w naszym zakleszczeniu to także 0x02b0f58d7730f798. Tekst tej instrukcji można zobaczyć w buforze wejściowym. W takim przypadku oba zapytania mają ten sam skrót planu zapytania, ponieważ zapytania są identyczne, z wyjątkiem wartości literału używanej jako predykat równości.

W dalszej części tego artykułu użyjemy tych wartości, aby znaleźć dodatkowe informacje w Query Store.

Ograniczenia buforu wejściowego na liście procesów zakleszczenia

Istnieją pewne ograniczenia dotyczące informacji o buforze wejściowym na liście procesów zakleszczenia.

Tekst zapytania może zostać obcięty w buforze wejściowym. Bufor wejściowy jest ograniczony do pierwszych 4000 znaków wykonywanej instrukcji.

Ponadto niektóre oświadczenia związane z impasem mogą nie być uwzględnione w grafie zakleszczenia. W naszym przykładzie sesja A uruchomiła dwie instrukcje aktualizacji w ramach jednej transakcji. Tylko druga instrukcja aktualizacji, aktualizacja, która spowodowała zakleszczenie, jest uwzględniona w grafie zakleszczenia. Pierwsza instrukcja aktualizacji uruchamiana przez sesję sesji A odegrała rolę w impasie, blokując sesji B. Bufor wejściowy, query_hashi powiązane informacje dotyczące pierwszej instrukcji uruchamianej przez sesji A nie są uwzględniane w grafie zakleszczenia.

Aby zidentyfikować pełne Transact-SQL uruchomienie w transakcji wieloinstrukcyjnej zaangażowanej w zakleszczenie, należy znaleźć odpowiednie informacje w procedurze składowanej lub kodzie aplikacji, które uruchomiły zapytanie, lub uruchomić ślad z pomocą zdarzeń rozszerzonych, aby rejestrować pełne instrukcje uruchamiane przez sesje uczestniczące w zakleszczeniu w momencie jego występowania. Jeśli instrukcja związana z zakleszczeniem jest obcięta i w buforze wejściowym pojawia się tylko częściowa Transact-SQL, można znaleźć Transact-SQL instrukcji w magazynie zapytań z planem wykonywania.

Lista zasobów zakleszczenia

Lista zasobów zakleszczenia pokazuje, które zasoby blokady są własnością i czekane przez procesy w impasie.

Zasoby są reprezentowane przez prostokąty w wizualnej reprezentacji zakleszczenia:

Zrzut ekranu przedstawiający wykres zakleszczenia wyświetlany wizualnie w programie SSMS. Prostokąty pokazują zasoby, które są zaangażowane w zakleszczenie.

Uwaga

Nazwy baz danych są reprezentowane jako identyfikatory GUID (uniqueidentifier) w grafach zakleszczenia dla baz danych w usłudze Azure SQL Database. Jest physical_database_name to element bazy danych wymieniony w bazach danych sys.databases i sys.dm_user_db_resource_governance dynamicznych widokach zarządzania.

W tym przykładzie zakleszczenia:

  • Ofiara zakleszczenia, którą nazwaliśmy sesją A:

    • Jest właścicielem blokady wyłącznej (X) na kluczu w indeksie PK_Product_ProductID w SalesLT.Product tabeli.

    • Żąda blokady aktualizacji (U) na kluczu w indeksie PK_ProductDescription_ProductDescriptionID w SalesLT.ProductDescription tabeli.

  • Drugi proces, który nazywamy sesją B:

    • Jest właścicielem blokady aktualizacji (U) na kluczu w indeksie PK_ProductDescription_ProductDescriptionID w SalesLT.ProductDescription tabeli.

    • Żąda blokady udostępnionej (S) na kluczu w indeksie PK_ProductDescription_ProductDescriptionID w SalesLT.ProductDescription tabeli.

Te same informacje są widoczne w kodzie XML grafu zakleszczenia w węźle lista zasobów.

Znajdowanie planów wykonywania zapytań w magazynie zapytań

Często przydatne jest sprawdzenie planów wykonania zapytań dotyczących operacji związanych z zakleszczeniem. Te plany wykonywania można często znaleźć w magazynie zapytań przy użyciu skrótu planu zapytania z widoku XML listy procesów grafu zakleszczenia.

To zapytanie Transact-SQL wyszukuje plany zapytań pasujące do skrótu planu zapytania, który znaleźliśmy na potrzeby naszego przykładowego zakleszczenia. Połącz się z bazą danych użytkownika w usłudze Azure SQL Database, aby uruchomić zapytanie.

DECLARE @query_plan_hash AS BINARY (8) = 0x02b0f58d7730f798;

SELECT qrsi.end_time AS interval_end_time,
       qs.query_id,
       qp.plan_id,
       qt.query_sql_text,
       TRY_CAST (qp.query_plan AS XML) AS query_plan,
       qrs.count_executions
FROM sys.query_store_query AS qs
     INNER JOIN sys.query_store_query_text AS qt
         ON qs.query_text_id = qt.query_text_id
     INNER JOIN sys.query_store_plan AS qp
         ON qs.query_id = qp.query_id
     INNER JOIN sys.query_store_runtime_stats AS qrs
         ON qp.plan_id = qrs.plan_id
     INNER JOIN sys.query_store_runtime_stats_interval AS qrsi
         ON qrs.runtime_stats_interval_id = qrsi.runtime_stats_interval_id
WHERE query_plan_hash = @query_plan_hash
ORDER BY interval_end_time, query_id;
GO

W zależności od ustawień magazynu zapytań CLEANUP_POLICY lubustawień QUERY_CAPTURE_MODE magazynu zapytań może nie być możliwe uzyskanie planu wykonywania zapytań z magazynu zapytań. W takim przypadku często można uzyskać potrzebne informacje , wyświetlając szacowany plan wykonania zapytania.

Poszukaj wzorców, które zwiększają blokowanie

Podczas badania planów wykonywania zapytań związanych z zakleszczeniami, poszukaj wzorców, które mogą przyczynić się do blokowania i zakleszczeń.

  • Skanowanie tabeli lub indeksu. Gdy zapytania modyfikujące dane są uruchamiane w obszarze RCSI, wybór wierszy do aktualizacji odbywa się przy użyciu skanowania blokującego, w którym blokada aktualizacji (U) jest wykonywana w wierszu danych w miarę odczytywania wartości danych. Jeśli wiersz danych nie spełnia kryteriów aktualizacji, blokada aktualizacji zostanie zwolniona, a następny wiersz zostanie zablokowany i zeskanowany.

    Dostrajanie indeksów w celu ułatwienia modyfikacji zapytań dotyczących znajdowania wierszy wydajniej zmniejsza liczbę wystawionych blokad aktualizacji. Zmniejsza to prawdopodobieństwo blokowania i zakleszczenia.

  • Indeksowane widoki odwołujące się do więcej niż jednej tabeli. Podczas modyfikowania tabeli, do której odwołuje się widok indeksowany, aparat bazy danych musi również obsługiwać indeksowany widok. Wymaga to wyjęcie większej liczby blokad i może prowadzić do zwiększenia blokowania i zakleszczenia. Widoki indeksowane mogą również spowodować, że operacje aktualizacji są wykonywane wewnętrznie w ramach poziomu izolacji zatwierdzonej do odczytu.

  • Modyfikacje kolumn, do których odwołuje się ograniczenia klucza obcego. Podczas modyfikowania kolumn w tabeli, do której odwołuje się ograniczenie FOREIGN KEY, aparat bazy danych musi szukać powiązanych wierszy w tabeli odwołującej się. Nie można używać wersji wierszy dla tych operacji odczytu. W przypadkach, gdy włączono aktualizacje lub usuwanie kaskadowe, poziom izolacji może być podniesiony do serializacji na czas wykonywania instrukcji, w celu ochrony przed wstawkami fantomowymi.

  • Zablokuj wskazówki. Poszukaj wskazówek tabeli, które określają poziomy izolacji wymagające większej liczby blokad. Te wskazówki obejmują HOLDLOCK (co jest równoważne serializacji), SERIALIZABLE, READCOMMITTEDLOCK (co wyłącza RCSI) i REPEATABLEREAD. Ponadto wskazówki, takie jak PAGLOCK, TABLOCK, UPDLOCKi XLOCK mogą zwiększyć ryzyko blokowania i zakleszczenia.

    Jeśli te wskazówki są w miejscu, badania, dlaczego wskazówki zostały wdrożone. Te wskazówki mogą zapobiec warunkom wyścigu i zapewnić ważność danych. W razie potrzeby można pozostawić te wskazówki i zapobiec przyszłym zakleszczeniom, stosując alternatywną metodę w sekcji Zapobieganie ponownemu wystąpieniu zakleszczenia tego artykułu.

    Uwaga

    Dowiedz się więcej o zachowaniu podczas modyfikowania danych przy użyciu przechowywania wersji wierszy w przewodniku Dotyczącym blokowania transakcji i przechowywania wersji wierszy.

Podczas badania pełnego kodu transakcji w planie wykonywania lub w kodzie zapytania aplikacji poszukaj dodatkowych problematycznych wzorców:

  • Interakcja użytkownika w transakcjach. Interakcja użytkownika wewnątrz jawnej transakcji obejmującej wiele instrukcji znacznie zwiększa czas trwania transakcji. To sprawia, że bardziej prawdopodobne jest, aby te transakcje nakładały się i blokowały i zakleszczenia.

    Podobnie przechowywanie otwartej transakcji i wykonywanie zapytań względem niepowiązanej bazy danych lub systemowej transakcji w połowie transakcji znacznie zwiększa prawdopodobieństwo blokowania i zakleszczenia.

  • Transakcje uzyskiwania dostępu do obiektów w różnych zamówieniach. Zakleszczenia są mniej prawdopodobne, gdy równoczesne transakcje z wieloma instrukcjami są zgodne z tymi samymi wzorcami i dostępem do obiektów w tej samej kolejności.

Zapobieganie zakleszczeniom

Dostępnych jest wiele technik, które zapobiegają ponownemu występowaniu zakleszczeń, takich jak dostrajanie indeksów, wymuszanie planów za pomocą Query Store i modyfikowanie zapytań Transact-SQL.

  • Przejrzyj indeks klastrowany tabeli. Większość tabel korzysta z indeksów klastrowanych, ale często tabele są implementowane w sposób przypadkowy.

    Jednym ze sposobów sprawdzenia indeksu klastrowanego jest użycie procedury składowanej systemu sp_helpindex . Na przykład możemy wyświetlić podsumowanie indeksów w SalesLT.Product tabeli, wykonując następującą instrukcję:

    EXECUTE sp_helpindex 'SalesLT.Product';
    GO
    

    Przejrzyj kolumnę index_description. Tabela może zawierać tylko jeden indeks klastrowany. Jeśli indeks klastrowany został zaimplementowany dla tabeli, index_description zawiera słowo clustered.

    Jeśli nie ma indeksu klastrowanego, tabela jest stertą. W takim przypadku sprawdź, czy tabela została celowo utworzona jako sterta w celu rozwiązania określonego problemu z wydajnością. Rozważ zaimplementowanie indeksu klastrowanego na podstawie wytycznych dotyczących projektowania indeksu klastrowanego.

    W niektórych przypadkach tworzenie lub dostrajanie indeksu klastrowanego może zmniejszyć lub wyeliminować blokowanie w impasach. W innych przypadkach możesz stosować dodatkową technikę, taką jak inne na tej liście.

  • utwórz lub zmodyfikuj indeksy nieklastrowane. Dostrajanie indeksów nieklastrowanych może pomóc w wyszukiwaniu danych w celu szybszego aktualizowania zapytań modyfikacji, co zmniejsza liczbę wymaganych blokad aktualizacji.

    W naszym przykładowym zakleszczeniu plan wykonywania zapytania znaleziony w magazynie zapytań zawiera skanowanie indeksu klastrowanego względem indeksu PK_Product_ProductID . Wykres zakleszczenia wskazuje, że współużytkowany (S) oczekiwanie na ten indeks jest składnikiem zakleszczenia.

    Zrzut ekranu przedstawiający plan wykonywania zapytania. Skanowanie indeksu klastrowanego jest wykonywane względem indeksu PK_Product_ProductID w tabeli Product.

    To skanowanie indeksu jest wykonywane, ponieważ nasze zapytanie aktualizacji musi zmodyfikować indeksowany widok o nazwie vProductAndDescription. Jak wspomniano w sekcji Szukaj wzorców zwiększających blokowanie tego artykułu, indeksowane widoki odwołujące się do wielu tabel mogą zwiększyć blokowanie i prawdopodobieństwo zakleszczenia.

    Jeśli utworzymy następujący indeks nieklastrowany w AdventureWorksLT bazie danych, który "obejmuje" kolumny z SalesLT.Product przywoływanego przez indeksowany widok, pomoże to zapytaniu znaleźć wiersze znacznie wydajniej:

    CREATE INDEX IX_Product_ProductID_Name_ProductModelID
        ON SalesLT.Product(ProductID, Name, ProductModelID);
    GO
    

    Po utworzeniu tego indeksu zakleszczenie nie będzie już powtarzane.

    Gdy zakleszczenia obejmują modyfikacje kolumn odwołujących się do ograniczeń klucza obcego, upewnij się, że indeksy w tabeli referencyjnej FOREIGN KEY umożliwiają efektywne znajdowanie powiązanych wierszy.

    Chociaż indeksy mogą znacznie poprawić wydajność zapytań w niektórych przypadkach, indeksy również mają koszty związane z obciążeniem i zarządzaniem. Zapoznaj się z ogólnymi wytycznymi dotyczącymi projektowania indeksów, aby ułatwić ocenę korzyści z indeksów przed utworzeniem indeksów, szczególnie szerokich indeksów i indeksów w dużych tabelach.

  • Oceń wartość indeksowanych widoków. Inną opcją zapobiegania ponownemu zakleszczaniu naszego przykładowego SalesLT.vProductAndDescription zakleszczenia jest usunięcie widoku indeksowanego. Jeśli ten widok indeksowany nie jest używany, zmniejsza to nakład pracy związany z utrzymywaniem indeksowanego widoku w czasie.

  • Użyj izolacji migawki. W niektórych przypadkach ustawienie poziomu izolacji transakcji do migawki dla jednej lub więcej transakcji biorących udział w zakleszczeniu może zapobiec blokowaniu i ponownemu wystąpieniu zakleszczeń.

    Ta technika najprawdopodobniej powiedzie się w przypadku użycia w instrukcjach SELECT, gdy migawki zatwierdzonej do odczytu jest wyłączona w bazie danych. Gdy migawka zatwierdzona do odczytu jest wyłączona, SELECT zapytania przy użyciu poziomu izolacji zatwierdzonej do odczytu wymagają blokad udostępnionych (S). Użycie izolacji migawki w tych transakcjach eliminuje konieczność blokowania udostępnionych blokad, co może uniemożliwić blokowanie i zakleszczenia.

    W bazach danych, w których włączono izolację zatwierdzonych migawek do odczytu, zapytania SELECT nie wymagają blokad współdzielonych (S), dlatego zakleszczenia mogą częściej występować między transakcjami, które modyfikują dane. W przypadkach, gdy zakleszczenia występują między wieloma transakcjami modyfikującymi dane, izolacja migawki może spowodować konflikt aktualizacji zamiast zakleszczenia. Podobnie wymaga to wykonania jednej z transakcji, aby ponowić próbę wykonania operacji.

  • Wymuś plan z magazynem zapytań. Może się okazać, że jedno z zapytań w impasie ma wiele planów wykonywania, a impas występuje tylko wtedy, gdy zostanie użyty określony plan. Możesz zapobiec ponownemu zakleszczaniu, wymuszając plan w magazynie zapytań.

  • Zmodyfikuj język Transact-SQL. Aby zapobiec ponownemu zakleszczeniu, może być konieczne zmodyfikowanie Transact-SQL. Należy starannie zmodyfikować język Transact-SQL, a zmiany powinny być rygorystycznie testowane, aby upewnić się, że dane są poprawne podczas równoczesnego uruchamiania modyfikacji. Podczas ponownego pisania języka Transact-SQL należy wziąć pod uwagę następujące kwestie:

    • Porządkowanie instrukcji w transakcjach w taki sposób, aby uzyskiwały dostęp do obiektów w tej samej kolejności.

    • Podział transakcji na mniejsze transakcje, gdy jest to możliwe.

    • W razie potrzeby użyj wskazówek dotyczących zapytań, aby zoptymalizować wydajność. Wskazówki można stosować bez zmieniania kodu aplikacji przy użyciu magazynu zapytań.

Znajdź więcej sposobów zminimalizowania zakleszczeń w przewodniku Zakleszczenia.

Uwaga

W niektórych przypadkach można dostosować priorytet impasu co najmniej jednej sesji biorącej udział w impasie, jeśli ważne jest, aby jedna z sesji zakończyła się pomyślnie bez konieczności ponawiania, lub gdy jedno z zapytań zaangażowanych w impas nie jest krytyczne i powinno być zawsze oznaczane jako ofiara. To nie zapobiega ponownym zakleszczeniom, jednak może zmniejszyć wpływ przyszłych zakleszczeń.

Usuwanie sesji XEvents

Możesz pozostawić sesję XEvents, która zbiera informacje o zakleszczeniach, działającą na krytycznych bazach danych przez długi czas. Jeśli używasz docelowego pliku zdarzeń, może to spowodować powstanie dużych plików, jeśli wystąpi wiele zakleszczeń. Możesz usuwać pliki obiektów blob z usługi Azure Storage podczas aktywnego śledzenia, z wyjątkiem pliku, do którego obecnie odbywa się zapis.

Jeśli chcesz usunąć sesję XEvents, sesja transact-SQL jest taka sama, niezależnie od wybranego typu docelowego.

Aby usunąć sesję XEvents, uruchom następujące polecenie Języka Transact-SQL. Przed uruchomieniem kodu zastąp nazwę sesji odpowiednią wartością.

ALTER EVENT SESSION [deadlocks] ON DATABASE
STATE = STOP;
GO

DROP EVENT SESSION [deadlocks] ON DATABASE;
GO

Korzystanie z Eksploratora usługi Azure Storage

Eksplorator usługi Azure Storage to autonomiczna aplikacja, która upraszcza pracę z obiektami docelowymi plików zdarzeń przechowywanymi w obiektach blob w usłudze Azure Storage. Za pomocą Eksplorator usługi Storage można wykonywać następujące czynności:

Pobierz Eksplorator usługi Azure Storage.