Błąd „Baza danych jest w trakcie przenoszenia”


12

Dzisiaj próbowałem przywrócić bazę danych do już istniejącej bazy danych, po prostu kliknąłem bazę danych prawym przyciskiem myszy w SSMS -> Zadania -> Przejdź do trybu offline, aby móc przywrócić bazę danych.

Przez Query Executing.....jakiś czas pojawiało się małe okienko wyskakujące, które wyświetlało komunikat błędu Database is in use cannot take it offline. Z którego zebrałem, istnieją pewne aktywne połączenia z tą bazą danych, więc próbowałem wykonać następujące zapytanie

USE master
GO
ALTER DATABASE My_DatabaseName
SET OFFLINE WITH ROLLBACK IMMEDIATE
GO

Znów w tym momencie SSMS pokazywał Query Executing.....przez jakiś czas, a następnie zgłosił następujący błąd:

Msg 5061, Level 16, State 1, Line 1
ALTER DATABASE failed because a lock could not be placed on database 'My_DatabaseName'. Try again later.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.

Po tym nie mogłem połączyć się z bazą danych przez SSMS. a kiedy próbowałem przełączyć go w tryb offline za pomocą SSMS, zgłosił błąd:

Database is in Transition. Try later .....

W tym momencie po prostu nie mogłem dotknąć bazy danych, cokolwiek próbowałem, zwróciło ten sam komunikat o błędzie Database is in Transition.

W Google przeczytałem kilka pytań, w których ludzie napotkali podobny problem i zalecili zamknięcie SSMS i otwarcie go ponownie, ja też. Ponieważ był to tylko serwer deweloperów, właśnie usunąłem bazę danych za pomocą SSMS i przywróciłem nową bazę danych.

Moje pytanie brzmi: co mogło to spowodować? i jak mogę tego uniknąć w przyszłości, a jeśli kiedykolwiek będę w tej samej sytuacji w przyszłości, czy jest jakiś inny sposób na naprawienie tego, niż usunięcie całej bazy danych?

Dziękuję Ci

Odpowiedzi:


24

Repro

  1. Otwórz SSMS
  2. Wpisz następujące polecenie w nowym oknie zapytania

    use <YourDatabase>;
    go
  3. Przejdź do Object Explorer (SSMS) i kliknij prawym przyciskiem myszy <YourDatabase>-> Tasks->Take Offline
  4. 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:

wprowadź opis zdjęcia tutaj

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_locksto 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ś, KILLto 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 IMMEDIATEnajprawdopodobniej wystarczyłbyś, gdybyś początkowo stwierdził, że wycofanie jest prawidłowe.



0

Nie musisz nic robić, po prostu zabij proces SqLWB.exez Menedżera zadań, otwórz SQL Server, kliknij bazę danych prawym przyciskiem myszy i przełącz ją w tryb offline. Jeśli to nie zadziała, po zabiciu sesji wpisz polecenie

ALTER DATABASE [Test4] SET OFFLINE WITH ROLLBACK IMMEDIATE

a następnie offline. Będzie działać tak samo, jak dla mnie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.