Repro
- Otwórz SSMS
Wpisz następujące polecenie w nowym oknie zapytania
use <YourDatabase>;
go
- Przejdź do Object Explorer (SSMS) i kliknij prawym przyciskiem myszy
<YourDatabase>
-> Tasks
->Take Offline
Otwórz drugie nowe okno zapytania i wpisz następujące polecenie:
use <YourDatabase>;
go
Zostaniesz poproszony o następujący komunikat:
Msg 952, poziom 16, stan 1, wiersz 1
Baza danych „TestDb1” jest w fazie przejściowej. Wypróbuj oświadczenie później.
Przyczynę tego można znaleźć na podstawie podobnego zapytania diagnostycznego do poniższego:
select
l.resource_type,
l.request_mode,
l.request_status,
l.request_session_id,
r.command,
r.status,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.wait_resource,
request_sql_text = st.text,
s.program_name,
most_recent_sql_text = stc.text
from sys.dm_tran_locks l
left join sys.dm_exec_requests r
on l.request_session_id = r.session_id
left join sys.dm_exec_sessions s
on l.request_session_id = s.session_id
left join sys.dm_exec_connections c
on s.session_id = c.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st
outer apply sys.dm_exec_sql_text(c.most_recent_sql_handle) stc
where l.resource_database_id = db_id('<YourDatabase>')
order by request_session_id;
Co jest warte, nie potrzebujesz Eksploratora obiektów, aby odtworzyć ten błąd. Potrzebujesz tylko zablokowanego żądania, które próbuje wykonać tę samą operację (w takim przypadku przełącz bazę danych w tryb offline). Zobacz poniższy zrzut ekranu dla trzech kroków w T-SQL:
Najprawdopodobniej zobaczysz, że twoja sesja Object Explorer jest blokowana przez inną sesję (pokazane przez blocking_session_id
). Ta sesja Object Explorer będzie próbowała uzyskać wyłączną blokadę ( X
) w bazie danych. W powyższym przypadku sesji Object Explorer przyznano blokadę aktualizacji ( U
) i próbę konwersji na blokadę wyłączną ( X
). Miał typ oczekiwania LCK_M_X
, zablokowany przez naszą sesję, który był reprezentowany przez pierwsze okno zapytania ( use <YourDatabase>
pobiera wspólną blokadę ( S
) w bazie danych).
A potem ten błąd pojawił się podczas kolejnej sesji próbującej uzyskać blokadę, a ten komunikat o błędzie powoduje odmowę sesji w celu uzyskania dostępu do bazy danych, która próbuje przejść do innego stanu (w tym przypadku stanu online do przejścia offline).
Co powinieneś zrobić następnym razem?
Po pierwsze, nie panikuj i nie zaczynaj zrzucać baz danych . Musisz zastosować metodę rozwiązywania problemów (z podobnym zapytaniem diagnostycznym, jak to powyżej), aby dowiedzieć się, dlaczego widzisz to, co widzisz. Przy takim komunikacie lub gdy coś wydaje się „zawieszone”, powinieneś automatycznie założyć brak współbieżności i zacząć kopać w blokowanie ( sys.dm_tran_locks
to dobry początek).
Na marginesie, naprawdę uważam, że najlepiej jest znaleźć przyczynę problemu przed podjęciem jakiegokolwiek losowego działania. Nie tylko przy tej operacji, ale dotyczy to wszystkich zachowań, których się nie spodziewasz. Wiedząc, co tak naprawdę spowodowało problem, to oczywiste, że to naprawdę nie była wielka sprawa. Zasadniczo miałeś łańcuch blokujący, a bloker nadrzędny był czymś, co najprawdopodobniej mógłeś właśnie wydać KILL
, lub jeśli było to żądanie sesji, którego nie chciałeś, KILL
to mógłbyś poczekać, aż się zakończy. Tak czy inaczej, miałbyś wiedzę, aby podjąć właściwą i rozważną decyzję, biorąc pod uwagę twój konkretny scenariusz (wycofanie lub oczekiwanie na zatwierdzenie).
Kolejna rzecz warta odnotowania, jest to jeden z powodów, dla których zawsze wybieram alternatywę T-SQL zamiast GUI. Wiesz dokładnie, co wykonujesz za pomocą T-SQL i co robi SQL Server. W końcu wydałeś jawne polecenie. Gdy używasz GUI, rzeczywisty T-SQL będzie abstrakcją. W tym przypadku spojrzałem na próbę zablokowania Eksploratora obiektów, aby przełączyć bazę danych w tryb offline i tak było ALTER DATABASE <YourDatabase> SET OFFLINE
. Nie było próby wycofania się, dlatego czekał w nieskończoność. W twoim przypadku, jeśli chcesz wycofać sesje, które miały blokady w tej bazie danych, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
najprawdopodobniej wystarczyłbyś, gdybyś początkowo stwierdził, że wycofanie jest prawidłowe.