Repro
- Abrir SSMS
Escriba lo siguiente en una nueva ventana de consulta
use <YourDatabase>;
go
- Vaya al Explorador de objetos (SSMS) y haga clic derecho en
<YourDatabase>
-> Tasks
->Take Offline
Abra una segunda ventana de consulta nueva y escriba lo siguiente:
use <YourDatabase>;
go
Se le solicitará el siguiente mensaje:
Msg 952, Nivel 16, Estado 1, Línea 1 La
base de datos 'TestDb1' está en transición. Prueba la declaración más tarde.
La razón por la que esto sucede puede encontrarse en una consulta de diagnóstico similar a la siguiente:
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 lo que vale, no necesita el Explorador de objetos para reproducir este error. Solo necesita una solicitud bloqueada que intente la misma operación (en este caso, desconecte la base de datos). Vea la captura de pantalla siguiente para los tres pasos en T-SQL:
Lo más probable es que veas que tu sesión de Object Explorer está bloqueada por otra sesión (mostrada por blocking_session_id
). Esa sesión de Object Explorer intentará obtener un bloqueo exclusivo ( X
) en la base de datos. En el caso de la reproducción anterior, a la sesión del Explorador de objetos se le otorgó un bloqueo de actualización ( U
) e intentó convertir a un bloqueo exclusivo ( X
). Tenía un wait_type de LCK_M_X
, bloqueado por nuestra sesión que estaba representada por la primera ventana de consulta ( use <YourDatabase>
toma un bloqueo compartido ( S
) en la base de datos).
Y luego, este error surgió de otra sesión que intentaba obtener un bloqueo, y este mensaje de error resulta en la denegación de una sesión para obtener acceso a una base de datos que está intentando realizar la transición a un estado diferente (en este caso, estado de conexión en línea a la transición fuera de línea).
¿Qué deberías hacer la próxima vez?
En primer lugar, no entre en pánico y no comience a soltar bases de datos . Debe adoptar un enfoque de solución de problemas (con una consulta de diagnóstico similar a la anterior) para averiguar por qué está viendo lo que está viendo. Con un mensaje como ese, o cuando algo parece "colgado", debe asumir automáticamente la falta de concurrencia y comenzar a cavar en el bloqueo ( sys.dm_tran_locks
es un buen comienzo).
Como nota al margen, realmente creo que es mejor averiguar la raíz de un problema antes de tomar cualquier acción aleatoria. No solo con esta operación, sino que se aplica a todos los comportamientos que no esperas. Sabiendo lo que realmente estaba causando su problema, es obvio que realmente no era gran cosa. Básicamente tenía una cadena de bloqueo, y el bloqueador principal era algo que probablemente podría haber emitido KILL
, o si era una solicitud de sesión que no deseaba KILL
, podría haber esperado hasta que se completara. De cualquier manera, habría tenido el conocimiento para tomar la decisión correcta y prudente dado su escenario particular (revertir o esperar para confirmar).
Otra cosa que vale la pena señalar, esta es una de las razones por las que siempre opto por la alternativa T-SQL en lugar de una GUI. Sabe exactamente lo que está ejecutando con T-SQL y qué está haciendo SQL Server. Después de todo, emitió el comando explícito. Cuando usa una GUI, el T-SQL real será una abstracción. En este caso, miré el intento del Explorador de objetos bloqueado de desconectar la base de datos y así fue ALTER DATABASE <YourDatabase> SET OFFLINE
. No hubo intentos de retroceder, por lo que estaba esperando indefinidamente. En su caso, si quisiera revertir las sesiones que tenían bloqueos en esa base de datos, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
probablemente habría sido suficiente si hubiera tomado la determinación inicial de que la reversión estaba bien.