Repro
- Abra o SSMS
Digite o seguinte em uma nova janela de consulta
use <YourDatabase>;
go
- Vá para o Object Explorer (SSMS) e clique com o botão direito do mouse em
<YourDatabase>
-> Tasks
->Take Offline
Abra uma segunda nova janela de consulta e digite o seguinte:
use <YourDatabase>;
go
Você será solicitado com a seguinte mensagem:
Msg 952, nível 16, estado 1, linha 1 O
banco de dados 'TestDb1' está em transição. Tente a afirmação mais tarde.
A razão pela qual isso está acontecendo pode ser encontrada em uma consulta de diagnóstico semelhante à abaixo:
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;
Para o que vale a pena, você não precisa do Object Explorer para reproduzir este erro. Você só precisa de uma solicitação bloqueada que está tentando a mesma operação (nesse caso, coloque o banco de dados offline). Veja a captura de tela abaixo para as três etapas no T-SQL:
O que você provavelmente verá é a sua sessão do Pesquisador de Objetos sendo bloqueada por outra sessão (mostrada por blocking_session_id
). Essa sessão do Object Explorer tentará obter um bloqueio exclusivo ( X
) no banco de dados. No caso da reprodução acima, a sessão do Pesquisador de Objetos recebeu um bloqueio de atualização ( U
) e tentou converter em um bloqueio exclusivo ( X
). Ele tinha um wait_type of LCK_M_X
, bloqueado por nossa sessão, representada pela primeira janela de consulta (a use <YourDatabase>
captura de um bloqueio compartilhado ( S
) no banco de dados).
E, em seguida, esse erro surgiu de mais uma sessão tentando obter um bloqueio, e essa mensagem de erro resulta na negação de uma sessão para obter acesso a um banco de dados que está tentando fazer a transição para um estado diferente (neste caso, o estado online para transição offline).
O que você deve fazer da próxima vez?
Primeiro, não entre em pânico e não comece a soltar bancos de dados . Você precisa adotar uma abordagem de solução de problemas (com uma consulta de diagnóstico semelhante à anterior) para descobrir por que está vendo o que está vendo. Com uma mensagem como essa, ou quando algo parecer "travado", você deve assumir automaticamente uma falta de simultaneidade e começar a procurar o bloqueio ( sys.dm_tran_locks
é um bom começo).
Como uma observação lateral, eu realmente acredito que é melhor descobrir a raiz de um problema antes de tomar qualquer ação aleatória. Não apenas com esta operação, mas com todos os comportamentos que você não espera. Sabendo o que realmente estava causando o seu problema, é óbvio que realmente não era grande coisa. Você basicamente tinha uma cadeia de bloqueio, e o bloqueador pai era algo que você provavelmente poderia ter emitido KILL
, ou se era uma solicitação de sessão que você não queria, KILL
então poderia ter esperado até que ela fosse concluída. De qualquer forma, você teria o conhecimento necessário para tomar a decisão certa e prudente, considerando seu cenário específico (reversão ou aguardar confirmação).
Outra coisa que vale a pena notar: essa é uma das razões pelas quais eu sempre opto pela alternativa T-SQL em vez de uma GUI. Você sabe exatamente o que está executando com o T-SQL e o que o SQL Server está fazendo. Afinal, você emitiu o comando explícito. Quando você usa uma GUI, o T-SQL real será uma abstração. Nesse caso, observei a tentativa bloqueada do Pesquisador de Objetos de colocar o banco de dados offline e estava ALTER DATABASE <YourDatabase> SET OFFLINE
. Não houve tentativa de reversão, e é por isso que estava esperando indefinidamente. No seu caso, se você quisesse reverter as sessões que tinham bloqueios nesse banco de dados, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
provavelmente seria suficiente se tivesse feito a determinação inicial de que a reversão estava correta.