Udostępnij za pośrednictwem


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

Dotyczy:Azure SQL DatabaseSQL database w Fabric

W tym artykule przedstawiono sposób identyfikowania zakleszczeń (deadlocków), używania wykresów zakleszczeń i magazynu zapytań do identyfikowania zapytań w impasie oraz planowania i testowania zmian, aby zapobiec ponownemu wystąpieniu zakleszczeń. 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ą się zakleszczać.

Jak występują zakleszczenia

Każda nowa baza danych w usłudze Azure SQL Database ma domyślnie włączone ustawienie bazy danych izolacji migawkowej na poziomie odczytu zatwierdzonego (RCSI). Blokowanie między sesjami odczytu danych i sesjami zapisu danych jest zminimalizowane w ramach RCSI, który używa wersjonowania 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 dwa lub więcej zadań trwale blokuje się nawzajem, ponieważ każde z nich ma blokadę zasobu, który drugie zadanie próbuje zablokować. Zakleszczenie jest również nazywane cykliczną zależnością: w przypadku zakleszczenia obejmującego dwa zadania, transakcja A ma zależność od transakcji B, a transakcja B zamyka cykl, 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 zakleszczeń silnika bazy danych okresowo sprawdza obecność zadań, które są w zakleszczeniu. 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 innym zadaniom w zakleszczeniu ukończenie swoich transakcji.

Uwaga

Dowiedz się więcej o kryteriach wybierania ofiary zakleszczenia w sekcji lista procesów zakleszczenia tego artykułu.

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

Aplikacja z transakcją wybraną jako ofiara zakleszczenia powinna spróbować ponownie wykonać transakcję, 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 opartej na 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ść danych na poziomie transakcji. Używa ona wersji wierszy do wybierania i aktualizowania wierszy. Aby użyć izolacji migawki, zapytania lub połączenia muszą jawnie ustawić poziom izolacji transakcji na SNAPSHOT. Można to zrobić tylko wtedy, gdy dla bazy danych jest włączona izolacja migawki.

Możesz sprawdzić, czy w języku Transact-SQL jest włączona izolacja danych RCSI i/lub izolacja migawkowa. 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 blokady jest generowane po tym, jak menedżer blokad w usłudze Azure SQL Database wykryje blokadę i wybierze transakcję jako ofiarę. Innymi słowy, jeśli skonfigurujesz alerty dotyczące zakleszczeń, powiadomienie zostanie wysłane, gdy tylko zostanie rozwiązane pojedyncze zakleszczenie. Użytkownik nie musi podejmować żadnych działań w związku z tym zakleszczeniem. 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 takim 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

Podejście minimalizujące ryzyko zapobiegania zakleszczeniom przed ponownym wystąpieniem polega zazwyczaj na dostrajaniu 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 definicjach indeksów nieklastrowanych, tworzenie lub modyfikowanie indeksu klastrowanego może być operacją wymagającą dużej liczby operacji we/wy i czasochłonną na większych tabelach z istniejącymi indeksami nieklastrowanymi. 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ć ponownego wystąpienia zakleszczeń.

  • Przepisanie kodu Transact-SQL dla jednej lub kilku transakcji, które uczestniczą w zakleszczeniu, może również pomóc w zapobieganiu takim sytuacjom. 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 ponownemu pojawieniu się zakleszczenia w tym artykule.

Monitorowanie i wysyłanie alertów o zakleszczeniach

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 możliwość wyświetlania wykresów zakleszczeń w trybie interaktywnego widoku wizualnego. Możesz używać innych klientów, takich jak Azure Data Studio, aby śledzić przykłady, ale być może będziesz mógł wyświetlać wykresy zakleszczenia tylko w formacie 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 przy użyciu AdventureWorksLT portalu Azure, Azure CLI lub PowerShell, wybierz wybrane podejście w przewodniku 'Szybki start: tworzenie pojedynczej bazy danych Azure SQL Database'.

Skonfiguruj alerty zakleszczeń w portalu Azure

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

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 zablokowań są bogatym źródłem informacji dotyczących procesów i blokad związanych z impasem. Aby zebrać wykresy zakleszczenia ze zdarzeniami rozszerzonymi (XEvents) w usłudze Azure SQL Database, przechwyć zdarzenie sqlserver.database_xml_deadlock_report.

Wykresy zakleszczenia można zbierać przy użyciu XEvents, wybierając jako cel bufor pierścieniowy lub plik 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 platforma początkowa 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 XEvents nie są dostępne, gdy aparat bazy danych zostanie ponownie uruchomiony z dowolnego powodu, na przykład w przypadku przełączenia awaryjnego. 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 kod przykładowy tworzy sesję XEvents, która rejestruje wykresy blokad w pamięci przy użyciu celu bufora pierścieniowego. 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ć i uruchomić sesję XEvents dla zdarzenia sqlserver.database_xml_deadlock_report, które zapisuje w buforze pierścieniowym celu, 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 wykonaj następujące polecenie Transact-SQL. Ten kod rozpoczyna jawną transakcję i uruchamia pojedynczą instrukcję, która aktualizuje tabelęSalesLT.Product. Aby to zrobić, transakcja uzyskuje blokadę aktualizacyjną (U) na jednym wierszu w tabeli SalesLT.Product, która jest następnie przekształcana w blokadę wyłą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 automatycznego zatwierdzania transakcji. Ta instrukcja aktualizuje tabelę SalesLT.ProductDescription . Aktualizacja ustawia blokadę aktualizacyjną (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';

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. Powinno wystąpić zakleszczenie, a sesja A zostanie wybrana jako jego ofiara. 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.

Jeśli skonfigurujesz alerty zakleszczenia w portalu Azure, powinieneś otrzymać powiadomienie wkrótce po wystąpieniu zakleszczenia.

Wyświetl wykresy 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 do zapisu w buforze pierścienia, możesz wykonywać zapytania dotyczące zakleszczeń przy użyciu następującego 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świetl i zapisz graf zakleszczenia w formacie XML

Wyświetlanie wykresu zakleszczenia w XML pozwala kopiować inputbuffer instrukcje Transact-SQL związane z zakleszczeniem. 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ć jego kod XML, wybierz wartość w kolumnie deadlock_xml z dowolnego wiersza. Otworzy to 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.

Zapisz graf zakleszczenia jako plik 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 zakleszczeniem oraz szybko zidentyfikować ofiarę 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 zapisywanie pliku XML z grafem zakleszczenia jako pliku 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 Plik, a następnie Otwórz, a potem Plik. Wybierz zapisany plik z .xdl rozszerzeniem .

    Teraz wykres zakleszczenia jest wyświetlany w SSMS jako wizualna reprezentacja 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 oznaczonymi jako owale i zasobami blokady jako prostokąty.

Analizowanie zablokowania dla usługi Azure SQL Database

Wykres zakleszczenia zwykle ma trzy węzły:

  • Lista ofiar. Identyfikator procesu ofiary zakleszczenia.

  • Lista procesów. Informacje o wszystkich procesach związanych z zablokowaniem. Wykresy zakleszczeń używają terminu "proces" do określania sesji, w której uruchomiona jest transakcja.

  • Lista zasobów. Informacje na temat zasobów zaangażowanych w zakleszczenie.

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

Lista ofiar deadlocku

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

Zrzut ekranu przedstawiający wizualne przedstawienie zakleszczenia. Owal reprezentujący proces wybrany jako ofiara jest przekreślony znakiem X.

W widoku XML grafu zakleszczeniavictim-list 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 biorących udział w zakleszczeniu.

Graficzne przedstawienie wykresu zakleszczenia przedstawia tylko podzbiór informacji zawartych w pliku XML wykresu zakleszczenia. Owale na wykresie zakleszczeń reprezentują proces, pokazując informacje, w tym:

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

  • Priorytet zakleszczenia sesji. Jeśli dwie sesje mają różne priorytety zakleszczenia, ta z niższym priorytetem zostaje 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órą taniej jest wycofać jako ofiarę 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 w programie SSMS. Dwa owale reprezentują procesy. Bufor wejściowy dla jednego procesu jest wyświetlony.

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

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

  • Skrót planu zapytania dla ostatniego polecenia uruchomionego 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 z logowaniem chrisqpublic.

  • Skrót planu zapytania SQL ostatniego zapytania uruchomionego przed zakleszczeniem przez naszą ofiarę 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 w liście procesów zakleszczonych

Należy wziąć pod uwagę kilka ograniczeń dotyczących informacji o buforze wejściowym w liście procesu 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ę A odegrała rolę w impasie, blokując Sesję B. Bufor wejściowy, query_hash, i powiązane informacje dotyczące pierwszej instrukcji uruchamianej przez Sesję A nie są uwzględniane w grafie zakleszczenia.

Aby zidentyfikować pełne polecenie Transact-SQL w transakcji wieloinstrukcyjnej zaangażowanej w zakleszczenie, należy znaleźć odpowiednie informacje w procedurze składowanej lub w kodzie aplikacji, które uruchomiły to zapytanie, lub przeprowadzić śledzenie za 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 została obcięta i w buforze wejściowym znajduje się tylko częściowy kod Transact-SQL, można znaleźć kod Transact-SQL dla tej instrukcji w magazynie zapytań wraz z planem wykonania.

Lista zasobów zakleszczenia

Lista zasobów zakleszczenia pokazuje, które zasoby blokady są posiadane i oczekiwane przez procesy w zakleszczeniu.

W wizualnej reprezentacji zakleszczenia zasoby są przedstawiane jako prostokąty.

Zrzut ekranu wykresu zakleszczenia w SSMS. Prostokąty pokazują zasoby zaangażowane w zakleszczenie.

Uwaga

Nazwy baz danych są reprezentowane jako identyfikatory GUID (uniqueidentifier) w grafach blokad dla baz danych w Azure SQL Database. To jest physical_database_name dla bazy danych wymienionej w dynamicznych widokach zarządzania sys.databases i sys.dm_user_db_resource_governance.

W tym przykładzie 'zakleszczenie':

  • Ofiara zakleszczenia, którą nazwaliśmy Sesja 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 na tabeli SalesLT.ProductDescription.

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

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

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

Możemy zobaczyć te same informacje w graficznym przedstawieniu zakleszczenia w XML w węźle lista-zasobów.

Znajdowanie planów wykonywania zapytań w magazynie zapytań

Często przydatne jest sprawdzenie planów wykonania zapytań uczestniczących w zakleszczeniu. Te plany wykonywania można często znaleźć w repozytorium zapytań, używając skrótu planu zapytania z widoku XML listy procesów w grafie zakleszczenia.

To zapytanie Transact-SQL wyszukuje plany zapytań odpowiadające skrótowi planu zapytania, który znaleźliśmy dla 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 trybie RCSI, wybór wierszy do aktualizacji jest przeprowadzany przy użyciu skanowania blokującego, podczas którego blokada aktualizacji (U) jest nakładana na wiersz 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 zwiększenia wydajności zapytań modyfikujących dane pomaga efektywniej znajdować wiersze, co 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 usunięcia większej liczby blokad i może prowadzić do częstszego blokowania i zakleszczeń. Widoki indeksowane mogą również spowodować, że operacje aktualizacji są wykonywane wewnętrznie w ramach poziomu izolacji zatwierdzonej do odczytu.

  • Modyfikacje kolumn referencyjnych w ograniczeniach 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 serializowalnego na czas trwania instrukcji, aby chronić przed wstawkami fantomowymi.

  • Wskazówki dotyczące blokady. 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ą wdrożone, zbadaj, dlaczego je zastosowano. 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 jest bardziej prawdopodobne, że te transakcje będą się nakładać, co prowadzi do blokad oraz zakleszczeń.

    Podobnie, trzymanie otwartej transakcji i wykonywanie zapytań do niepowiązanej bazy danych lub systemu w trakcie trwania transakcji znacznie zwiększa prawdopodobieństwo blokowania i zakleszczeń.

  • Transakcje uzyskujące dostęp do obiektów w różnej kolejności. Zakleszczenia są mniej prawdopodobne, gdy równoczesne wieloetapowe transakcje przestrzegają tych samych wzorców i uzyskują dostęp do obiektów w tej samej kolejności.

Zapobieganie ponownemu wystąpieniu zakleszczenia

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 klastrowany indeks tabeli. Większość tabel korzysta z indeksów klastrowanych, ale często tabele są implementowane jako stosy przez pomyłkę.

    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 w formie sterty, aby rozwiązać określony problem 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 Twoim zapytaniom modyfikacji szybciej znajdować dane do aktualizacji, co zmniejsza liczbę wymaganych blokad aktualizacji.

    W naszym przykładowym zakleszczeniu plan wykonywania zapytania znaleziony w Query Store zawiera przeszukiwanie indeksu klastrowanego na indeksie PK_Product_ProductID. Wykres zakleszczenia wskazuje, że oczekiwanie na blokadę współdzieloną (S) na tym indeksie 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 już się nie powtarza.

    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 wystąpieniu naszego przykładowego zakleszczenia jest porzucenie indeksowanego widoku. 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 na migawkę 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 w bazie danych migawka potwierdzonego odczytu jest wyłączona. 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 potrzebę stosowania wspólnych blokad, co może zapobiegać blokowaniu i zakleszczeniom.

    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, aby jedna z transakcji ponownie wykonała operację.

  • Wymuś plan przy użyciu Query Store. 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 Query Store.

  • Zmodyfikuj język Transact-SQL. Aby uniknąć ponownego zakleszczenia, może być konieczne zmodyfikowanie kodu 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 Query Store.

Znajdź więcej sposobów zminimalizowania zakleszczeń w przewodniku dotyczącym zakleszczeń.

Uwaga

W niektórych przypadkach można dostosować priorytet zablokowania jednej lub więcej sesji biorących udział w zablokowaniu, jeśli ważne jest, aby jedna z sesji zakończyła się pomyślnie bez ponownego próbowania, lub gdy jedno z zapytań zaangażowanych w zablokowanie nie jest krytyczne i powinno być zawsze wybierane jako ofiara. To nie zapobiega ponownym zakleszczeniom, jednak może zmniejszyć wpływ przyszłych zakleszczeń.

Usuwanie sesji XEvents

Możesz pozostawić działającą na krytycznych bazach danych sesję XEvents, która zbiera informacje o zakleszczeniach, 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 Blob z usługi Azure Storage podczas aktywnego śledzenia, z wyjątkiem pliku, do którego aktualnie trwa zapis.

Jeśli chcesz usunąć sesję XEvents, polecenie Transact-SQL do usunięcia sesji jest takie samo, 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. Użyj Eksploratora magazynu, aby:

Pobierz Eksplorator usługi Azure Storage.