Sleeping SPID blokuje inne transakcje

16

Naprawdę mam problemy ze śledzeniem blokowania, którego doświadczamy.

Rdzeń blokujący status SPID to „spanie”, cmd to „OCZEKUJĄCE POLECENIE” i tak sqltextjest SET TRANSACTION ISOLATION LEVEL READ COMMITTED.

Kiedy przeglądam raport Najważniejsze transakcje według liczby zablokowanych transakcji, blokująca instrukcja SQL ma wartość „-”.

Przeprowadziłem śledzenie SQL, a kiedy następuje blokowanie, śledzenie SPID blokującego rootowanie, ale tak naprawdę nigdzie mnie to nie doprowadziło. Ostatnia instrukcja śledzenia jest taka sama jak sqltextpowyżej SET TRANSACTION ISOLATION LEVEL READ COMMITTED.

Sprawdziłem wszystkie powiązane procedury przechowywane, które mogę znaleźć, aby upewnić się, że mają TRY / CATCH BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN (używamy procedur przechowywanych do wszystkiego, więc nie są uruchamiane samodzielne instrukcje). Ten problem zaczął się pojawiać w ciągu ostatnich 24 godzin i nikt nie twierdzi, że wprowadził jakiekolwiek zmiany w systemie.

Rozwiązanie: jedna z naszych rzadko używanych procedur przechowywanych miała błąd z wstawką (liczba kolumn nie pasowała), ale nadal jesteśmy zdezorientowani, co dokładnie się dzieje.

Przeglądając wszystkie informacje śledzenia, instrukcja EXEC dla tej procedury składowanej była wymieniona czasami, ale NIGDY nie przed wystąpieniem BLOKU na blokującym SPID. Wydawało się, że kiedy zaczyna się blokować, ślad nie rejestruje jego wykonania (ani żadnej z zawartych w nim instrukcji). Jednak zdarzają się inne czasy, gdy ślad zarejestrował jego wykonanie i nie nastąpiło blokowanie.

Raport o błędzie procedury składowanej pochodzi od użytkownika, a ja byłem w stanie znaleźć wiele instrukcji EXEC w plikach śledzenia i uruchomić je w SSMS. Nie miałem czasu, kiedy je prowadziłem, czy zdarzyło się, że nastąpiło jakieś zablokowanie, czy też się zawiesiły. Działały zgodnie z oczekiwaniami (blok catch został uruchomiony i wycofał transakcję po błędzie). Po rozwiązaniu problemu z procedurą przechowywaną problem nie pojawił się ponownie.

Ćwiek
źródło
Zakładam, że nazwa hosta blokującego SPID wcale nie pomogła?
Jon Seigel
Nie, to tylko adres IP jednego z naszych serwerów ... Mamy inny pomysł, aby zmienić każde logowanie SQL dla każdego wywołania SPROC podczas procesu logowania / rejestracji (w którym naszym zdaniem występuje błąd) na osobną nazwę użytkownika, która może pomóż nam ustalić, który SPROC może powodować blokowanie.
Brad
1
TRY / CATCH nie wykryje błędów kompilacji, a niedopasowana wstawka kolumny byłaby takim błędem kompilacji. To również nigdy nie uruchomiłoby wielu zdarzeń profilera XX: Ukończone.
Remus Rusanu,
1
W rzeczywistości nie jest to błąd kompilacji, ponieważ genialny programista użył INSERT INTO [tabela] WYBIERZ * z [innej tabeli] i nie został złapany w peer. Uruchomiłem SPROC w dziale rozwoju 1000 razy od ColdFusion w 3 równoczesnych sesjach i nigdy nie pozostawiło otwartej transakcji, jak w przypadku produkcji.
Brad

Odpowiedzi:

10

Z komentarzy domyślam się, że upłynął limit czasu poleceń po stronie klienta, który przerwał zapytanie SQL. Nie powoduje to wycofania transakcji, ponieważ połączenie pozostaje otwarte na serwerze SQL Server ze względu na pule połączeń.

Musisz więc użyć SET XACT_ABORT ON lub dodać kod wycofania klienta

Zobacz Limit czasu transakcji SQL Server dla wszystkich krwawych szczegółów

gbn
źródło
Wszystkie nasze SPROC zawierają bloki TRY / CATCH oraz BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN, ROLLBACK jest w POŁOWIE. Czy XACT_ABORT nadal miałby wpływ?
Brad
@Brad: tak. Zobacz mój link. Blok catch nie został trafiony w CommandTimeout
gbn
gbn: Dzięki. Wciąż jestem zdezorientowany. Nasze połączenia ustawione są na limit czasu nigdy (0). Więc mówisz, że jeśli ponownie wykorzystamy połączenia, a połączenie uruchomi SPROC z błędem (który ma bloki TRY / CATCH i TRAN), to w jakiś sposób nigdy nie uruchomi funkcji ROLLBACK w bloku CATCH, blokując w ten sposób tabele i utrzymując transakcję otwarty? To nie ma dla mnie sensu.
Brad
@Brad: SPROC z błędem trafi w blok CATCH. Nie powiedziałem inaczej ani inaczej. Ale mój link mówi, co się stanie, jeśli masz CommandTimeout, który różni się od ConnectionTimeout. Klient mówi „przerwać”, a SQL Server przestaje przetwarzać. Ergo, blok CATCH, wycofanie lub zatwierdzenie nigdy nie zostało trafione
gbn
Nie sądzę, że mamy określony CommandTimeout. Wszystkie nasze procedury składowane są testowane przy użyciu narzędzia sqlstress i muszą działać poniżej 1000 ms przy 10 użytkownikach 10 iteracji (co najmniej). Nadal jestem bardzo zdezorientowany co do tego, co się stało, ale aktualizuję pytanie o to, co znaleźliśmy.
Brad
9

Użyj most_recent_sql_handle w sys.dm_exec_connections, aby zobaczyć ostatnią wykonaną instrukcję.

SELECT  t.text,
        QUOTENAME(OBJECT_SCHEMA_NAME(t.objectid, t.dbid)) + '.'
        + QUOTENAME(OBJECT_NAME(t.objectid, t.dbid)) proc_name,
        c.connect_time,
        s.last_request_start_time,
        s.last_request_end_time,
        s.status
FROM    sys.dm_exec_connections c
JOIN    sys.dm_exec_sessions s
        ON c.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) t
WHERE   c.session_id = 72;--your blocking spid

Sprawdź także, czy istnieją otwarte transakcje dla tego spid

SELECT  st.transaction_id,
        at.name,
        at.transaction_begin_time,
        at.transaction_state,
        at.transaction_status
FROM    sys.dm_tran_session_transactions st
JOIN    sys.dm_tran_active_transactions at
        ON st.transaction_id = at.transaction_id
WHERE   st.session_id = 72;--your blocking spid
Sebastian Meine
źródło
Możesz także użyć, DBCC INPUTBUFFER(spid)aby zobaczyć ostatni wykonany SQL.
Mike Fal
Użyłem tych wszystkich i ostatnie polecenie jest zawsze tym, co umieszczam w moim oryginalnym poście: USTAW POZIOM IZOLACJI PRZECZYTAJ ZOBOWIĄZANO. Uruchomiłem również DBCC OPENTRAN i widzę, że istnieje otwarta transakcja dla blokującego PID.
Brad
Mój pierwszy wybór podaje również nazwę procedury, jeśli instrukcja rzeczywiście jest częścią procedury.
Sebastian Meine
Zapewniam cię, że nie używamy żadnych zapytań adhoc z naszych serwerów internetowych, a kiedy uruchamiam to pierwsze zapytanie, nawet bez klauzuli WHERE otrzymuję tylko nazwany SPROC na kilku sesjach SQL, reszta tej kolumny ma wartość NULL.
Brad
Zauważam, że mam mnóstwo sesji z napisem „USTAW POZIOM IZOLACJI PRZECZYTAJ ZOBOWIĄZANO” i wszystkie z nich pochodzą z ColdFusion (głównego skryptu używanego na naszych serwerach internetowych). Być może ColdFusion, gdy bezczynny wydaje tę instrukcję, aby utrzymać otwarte połączenie (ponieważ jest ustawione, aby utrzymywać otwarte połączenia).
Brad
4

Czy próbowałeś używać sp_whoisactive Adama Machanica ? Istnieje opcja uzyskania zewnętrznego polecenia, aby sprawdzić, czy naprawdę znajduje się w proc. Możliwe, że aplikacja wstrzymuje otwartą transakcję zamiast jej zatwierdzenia. Spróbuj także spojrzeć na DBCC OPENTRAN .

Eric Humphrey - lotsahelp
źródło
Dzięki za DBCC OPENTRAN. Mówi mi to, że blokujący PID ma otwartą transakcję, ale nie są dostępne żadne dalsze szczegóły. sp_whoisactive zwraca te same informacje o zablokowanym procesie, które udało mi się uzyskać samodzielnie. Nadal nie ma żadnych szczegółów na temat tego, co się dzieje poza „ZESTAWIENIE POZIOMU ​​IZOLACJI ODCZYNNIKA PRZECZYTAJ ZOBOWIĄZANE”
Brad