Znajdź blokujące sesje w SQL Server: darmowy podgląd na żywo w SSMS, bez AI

Zapytanie wisi, a pytanie brzmi: kto kogo blokuje. SQL Sage dla SSMS odpowiada na żywo, za darmo i bez AI — a KILL zostaje skryptem, który uruchamiasz sam.

Zapytanie, które powinno zająć sekundę, wciąż się kręci. SSMS nie pokazuje błędu — tylko animację postępu i kursor, który nie chce wrócić. Coś trzyma blokadę, której potrzebuje Twoja instrukcja, i dopóki nie wiesz co, zgadujesz. To najstarsze pytanie w utrzymaniu baz i jedyne, które liczy się w tej chwili: kto kogo blokuje?

SQL Sage dla SSMS odpowiada na nie na miejscu, za darmo i bez AI. Widok na żywo o nazwie What’s blocking now — część SQL Sage History — pokazuje blokady dziejące się na serwerze w tym momencie: która sesja czeka, która trzyma blokadę i — częściej, niż myślisz — cichego winowajcę całej sytuacji.

Ujawnienie: ten blog publikuje LumaSoft (LUMA sp. z o.o.), a ja pracuję nad opisanym tu narzędziem.

Kto kogo blokuje: zapytanie T-SQL na DMV

Zanim o narzędziu — odpowiedź, którą dostaniesz w każdym oknie zapytania, bez instalowania czegokolwiek. SQL Server wystawia bieżące żądania w sys.dm_exec_requests, a kolumna blocking_session_id mówi, na którą sesję czeka dane żądanie (Microsoft Learn: sys.dm_exec_requests). Dołącz sys.dm_exec_sessions, żeby wiedzieć, kto to jest (Microsoft Learn: sys.dm_exec_sessions), oraz sys.dm_exec_sql_text, żeby zobaczyć, co wykonuje. Zapytanie tylko czyta widoki systemowe i jest poprawne na SQL Server 2016+ oraz Azure SQL — a to, ile zobaczysz, zależy od uprawnień (o tym niżej):

-- Kto kogo blokuje: żądania, które teraz czekają na inną sesję (tylko odczyt)
SELECT
    r.session_id,
    r.blocking_session_id,
    r.wait_type,
    r.wait_time                AS wait_time_ms,
    r.wait_resource,
    r.status,
    s.login_name,
    s.host_name,
    s.program_name,
    DB_NAME(r.database_id)     AS database_name,
    SUBSTRING(t.text,
              r.statement_start_offset / 2 + 1,
              (CASE r.statement_end_offset
                   WHEN -1 THEN DATALENGTH(t.text)
                   ELSE r.statement_end_offset
               END - r.statement_start_offset) / 2 + 1) AS statement_text
FROM sys.dm_exec_requests AS r
JOIN sys.dm_exec_sessions AS s
    ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.blocking_session_id <> 0
ORDER BY r.wait_time DESC;

Jak to czytać: każdy wiersz to sesja, która czeka, a blocking_session_id wskazuje, na kogo. wait_type zaczynający się od LCK_M_ oznacza czekanie na blokadę (np. LCK_M_X — na blokadę wyłączną), wait_time_ms mówi, jak długo to trwa, a wait_resource — o jaki zasób chodzi (klucz, strona, obiekt). statement_text to konkretna instrukcja z batcha, która stoi, a nie cały batch. Wartości ujemne w blocking_session_id to przypadki specjalne opisane w dokumentacji (np. -2 to osierocona transakcja rozproszona).

Łańcuch blokad ma głowę: sesję, która blokuje innych, a sama na nikogo nie czeka. Często w ogóle nie ma jej w sys.dm_exec_requests, bo niczego w tej chwili nie wykonuje — dlatego szukaj jej w sys.dm_exec_sessions:

-- Głowa łańcucha: sesje, które blokują innych, a same nie są zablokowane
SELECT
    s.session_id,
    s.status,
    s.login_name,
    s.host_name,
    s.program_name,
    s.open_transaction_count,
    s.last_request_end_time
FROM sys.dm_exec_sessions AS s
WHERE s.session_id IN (SELECT r.blocking_session_id
                       FROM sys.dm_exec_requests AS r
                       WHERE r.blocking_session_id > 0)
  AND NOT EXISTS (SELECT 1
                  FROM sys.dm_exec_requests AS r2
                  WHERE r2.session_id = s.session_id
                    AND r2.blocking_session_id > 0);

Głowa ze statusem sleeping i open_transaction_count większym od zera to klasyczny obraz: transakcja otwarta, praca skończona, blokady wciąż trzymane — więcej o tym niżej. Jedno zastrzeżenie: bez uprawnień widzisz tylko własną sesję. Na SQL Server do 2019 potrzebne jest VIEW SERVER STATE, od SQL Server 2022 — VIEW SERVER PERFORMANCE STATE; na Azure SQL Database dokumentacja sys.dm_exec_requests podaje, że widok jest ograniczony do bieżącego połączenia. Pusty wynik nie znaczy więc automatycznie „brak blokad”.

Nie zabijaj na ślepo. KILL na sesji z otwartą transakcją wycofuje całą jej pracę, a rollback potrafi trwać tyle co sama praca albo dłużej — przez cały ten czas blokady zostają. Najpierw sprawdź login_name, host_name i program_name: czy to zadanie ETL, czyjaś sesja w SSMS, czy pula połączeń aplikacji, która i tak otworzy połączenie na nowo. Jeśli możesz, poproś właściciela o COMMIT albo ROLLBACK. A gdy już uruchomisz KILL, postęp wycofywania pokaże KILL <session_id> WITH STATUSONLY.

Te dwa zapytania warto mieć w zakładkach. Jeśli wolisz nie trzymać ich w schowku na czas awarii, SQL Sage dla SSMS pokazuje ten sam obraz jako widok na żywo.

Co pokazuje „What’s blocking now”

Otwórz What’s blocking now, a dostajesz żywy obraz rywalizacji o blokady na serwerze — a nie zapytanie, które musisz sam napisać i zapamiętać. Widać, kto kogo blokuje, jakie otwarte transakcje są w to zamieszane, a widok oznacza sesję, która prawdopodobnie jest Twoja — więc nie czytasz ściany sesji, próbując dociec, który wiersz to Ty.

Ten ostatni szczegół znaczy więcej, niż brzmi. W realnej awarii działasz pod presją, lista jest nieznana, a pierwszy błąd, jaki ludzie popełniają, to działanie na niewłaściwej sesji. Wskazanie, który wiersz to najpewniej Twoje połączenie, usuwa całą kategorię pomyłek z paniki, zanim czegokolwiek dotkniesz.

Zwykły podejrzany: bezczynna sesja z otwartą transakcją

Gdy serwer staje, odruch każe szukać potwora — jakiegoś raportu skanującego miliard wierszy. Często wcale nie o to chodzi. Blokującym jest sesja, która nic nie robi: ktoś otworzył transakcję, uruchomił jedną instrukcję i odszedł — albo aplikacja rozpoczęła transakcję i nigdy nie wysłała COMMIT. Praca dawno skończona; blokady wciąż trzymane; wszyscy inni czekają w kolejce za połączeniem, które jest bezczynne.

Dokładnie dlatego surowa lista sesji potrafi zmylić. Bezczynna sesja wygląda niewinnie — zero CPU, żadne zapytanie się nie wykonuje — więc podejrzewasz ją na końcu, a bywa przyczyną. What’s blocking now wydobywa otwarte transakcje i oznacza tę bezczynną-lecz-trzymającą sesję wprost, więc przestajesz gonić rozpędzone zapytanie i znajdujesz połączenie, które naprawdę musi zniknąć.

KILL i GRANT to skrypty, nie przyciski

Tu jesteśmy najbardziej rozmyślni. SQL Sage nie sięga do serwera i nie kończy sesji za Ciebie. Gdy zdecydujesz, że połączenie trzeba ubić — albo nadać uprawnienie, żeby coś odblokować — SQL Sage podaje Ci KILL (lub GRANT) jako skrypt w nowym oknie zapytania. Nic więcej. Nic nie uruchamia się samo, a naciśnięcie F5 pyta, zanim KILL faktycznie się wykona.

To nie opór dla samego oporu; to ta sama zasada, która przewija się przez cały produkt, ta, o której pisaliśmy szerzej: narzędzie powinno pokazać Ci dokładną instrukcję i pozwolić, by spust pociągnął człowiek — zwłaszcza gdy działanie jest nieodwracalne. Ubicie niewłaściwej sesji na produkcji to rodzaj błędu, którego nie cofniesz. Dlatego diagnoza jest natychmiastowa i automatyczna; akt destrukcyjny to instrukcja, którą czytasz, celujesz i uruchamiasz sam.

SQL Sage History: co uruchomiłeś i kiedy

Diagnoza blokad to połowa sprawy. Druga połowa, w trakcie awarii i po niej, to odtworzenie, co Ty zrobiłeś — który skrypt uruchomiłeś na którym serwerze i czy zadziałał.

SQL Sage History zapisuje każde zapytanie, które uruchamiasz w SSMS. Trzymane jest wyłącznie na tym komputerze i szyfrowane dla Twojego konta Windows (DPAPI) — nigdzie nie jest wysyłane. Każdy wpis niesie serwer, bazę, status (w tym numer błędu SQL Server przy nieudanym uruchomieniu), czas trwania, liczbę zwróconych wierszy oraz to, czy była to instrukcja READ, WRITE czy DDL. Lista jest od najnowszych i przeszukiwalna, więc „ten ALTER, który uruchomiłem dwadzieścia minut temu na tamtym serwerze” to szybkie znalezienie, a nie grzebanie w pamięci.

Dwie rzeczy są z projektu niedostępne. Wyniki zapytań nigdy nie są zapisywane — tylko instrukcje, nie dane, które zwróciły. A hasła i inne sekrety (na przykład w CREATE LOGIN) są zamieniane na ?, zanim cokolwiek się zapisze; reszta tekstu zostaje tak, jak ją wpisałeś. Gdy chcesz coś uruchomić ponownie, „Open in new window” łączy się ponownie z tym samym serwerem i otwiera skrypt — nic nie uruchamia. Retencja to domyślnie 30 dni, a wstrzymać ją lub wyłączyć możesz, kiedy chcesz.

Recently closed: karta, którą odzyskasz

Awarie to moment, w którym karty zamyka się w pośpiechu. Miałeś skrypt diagnostyczny w połowie gotowy, coś innego zaczęło się palić, a karta przepadła — niezapisana. Recently closed (unsaved) przechowuje karty zapytań zamknięte bez zapisu, więc zgubiony skrypt można otworzyć ponownie, zamiast odtwarzać go z pamięci dokładnie wtedy, gdy najmniej Cię na to stać.

Gdzie to działa — i gdzie Incident Mode idzie dalej

Wszystko powyższe jest darmowe i nie używa AI. Działa świadomie edycji na pudełkowym SQL Server i na Azure SQL; część możliwości zależnych od DMV na poziomie serwera zachowuje się inaczej na Azure SQL Database, bo platforma udostępnia tam mniej, a SQL Sage korzysta z tego, co dana platforma faktycznie oferuje.

Żeby być uczciwym co do granicy: What’s blocking now odpowiada na „kto kogo blokuje, teraz”. Gdy chcesz pełnego kształtu dławiącego się serwera — całego łańcucha blokad, najczęstszych oczekiwań (top waits) i najdroższych zapytań, z każdym twierdzeniem popartym realną liczbą z DMV — to Incident Mode, część płatnej, wspieranej przez AI warstwy Proven & Accountable. Jest też uczciwy co do własnych ograniczeń: jeśli Twój login nie widzi innych sesji, mówi to wprost, zamiast raportować uspokajające „brak blokad”. Ale na natychmiastowe pytanie, które przerywa Ci dzień, darmowy widok na żywo wystarcza sam.

Wnioski

Gdy zapytanie wisi, nie potrzebujesz teorii — potrzebujesz zobaczyć, kto kogo blokuje, a odpowiedzią jest zwykle bezczynna sesja siedząca na otwartej transakcji. SQL Sage dla SSMS stawia tę odpowiedź o jedno kliknięcie dalej, za darmo i bez AI, bez wychodzenia z narzędzia, w którym już jesteś. Wydobywa prawdziwego winowajcę, oznacza, która sesja jest Twoja, i trzyma część destrukcyjną — KILL, GRANT — jako skrypt, który czytasz i uruchamiasz, a nie coś, co odpala się samo. SQL Sage History daje zapis tego, co i kiedy uruchomiłeś, a Recently closed łapie kartę, którą zamknąłeś w pośpiechu.

SQL Sage dla SSMS to dodatek do SQL Server Management Studio, który umieszcza asystenta AI w edytorze zapytań — pisze, objaśnia i optymalizuje SQL ugruntowany w Twoim prawdziwym schemacie — pozostaje domyślnie w trybie tylko do odczytu i jest bezkluczowy (logujesz się własnym kontem Claude lub ChatGPT, bez klucza API do zarządzania). Opisane wyżej widok blokad, SQL Sage History i Recently closed to część darmowego poziomu i nie używają AI w ogóle. Zobaczysz go na stronie produktu SQL Sage dla SSMS. SQL Sage tworzy LumaSoft (LUMA sp. z o.o.) i nie jest związany z Microsoftem.

← Wróć do bloga