Repro
- Ouvrez SSMS
Tapez ce qui suit dans une nouvelle fenêtre de requête
use <YourDatabase>;
go
- Accédez à l'Explorateur d'objets (SSMS) et cliquez avec le bouton droit sur
<YourDatabase>
-> Tasks
->Take Offline
Ouvrez une deuxième nouvelle fenêtre de requête et tapez ce qui suit:
use <YourDatabase>;
go
Vous serez invité avec le message suivant:
Msg 952, niveau 16, état 1, la
base de données de la ligne 1 «TestDb1» est en transition. Essayez la déclaration plus tard.
La raison pour laquelle cela se produit peut être trouvée à partir d'une requête de diagnostic similaire à celle ci-dessous:
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;
Pour ce que ça vaut, vous n'avez pas besoin de l'Explorateur d'objets pour reproduire cette erreur. Vous avez juste besoin d'une demande bloquée qui tente la même opération (dans ce cas, mettez la base de données hors ligne). Voir la capture d'écran ci-dessous pour les trois étapes de T-SQL:
Ce que vous verrez probablement, c'est que votre session Object Explorer est bloquée par une autre session (indiquée par blocking_session_id
). Cette session Object Explorer essaiera d'obtenir un verrou exclusif ( X
) sur la base de données. Dans le cas de la repro ci-dessus, la session Object Explorer a obtenu un verrou de mise à jour ( U
) et a tenté de se convertir en verrou exclusif ( X
). Il y avait un wait_type de LCK_M_X
, bloqué par notre session qui était représenté par la première fenêtre de requête (la use <YourDatabase>
capture un verrou partagé ( S
) sur la base de données).
Et puis cette erreur est survenue à partir d'une autre session essayant d'obtenir un verrou, et ce message d'erreur entraîne le refus d'une session pour accéder à une base de données qui tente de passer à un état différent (dans ce cas, l'état de connexion en ligne à la transition hors ligne).
Que devez-vous faire la prochaine fois?
Tout d'abord, ne paniquez pas et ne commencez pas à supprimer des bases de données . Vous devez adopter une approche de dépannage (avec une requête de diagnostic similaire à celle ci-dessus) pour savoir pourquoi vous voyez ce que vous voyez. Avec un message comme ça, ou quand quelque chose apparaît "bloqué", vous devez automatiquement supposer un manque de simultanéité et commencer à creuser dans le blocage ( sys.dm_tran_locks
c'est un bon début).
En passant, je crois vraiment que vous êtes mieux de découvrir la racine d'un problème avant de prendre une mesure aléatoire. Pas seulement avec cette opération, mais cela vaut pour tous les comportements auxquels vous ne vous attendez pas. Sachant ce qui a vraiment causé votre problème, il est évident que ce n'était vraiment pas grave. Vous aviez essentiellement une chaîne de blocage, et le bloqueur parent était quelque chose que vous auriez probablement pu émettre KILL
, ou si c'était une demande de session que vous ne vouliez pas, KILL
vous auriez pu attendre la fin. Quoi qu'il en soit, vous auriez eu les connaissances nécessaires pour prendre la bonne décision et prudente compte tenu de votre scénario particulier (restauration ou attente de validation).
Une autre chose à noter, c'est l'une des raisons pour lesquelles j'ai toujours opté pour l'alternative T-SQL au lieu d'une interface graphique. Vous savez exactement ce que vous exécutez avec T-SQL et ce que fait SQL Server. Après tout, vous avez lancé la commande explicite. Lorsque vous utilisez une interface graphique, le T-SQL réel sera une abstraction. Dans ce cas, j'ai regardé la tentative bloquée de l'Explorateur d'objets de mettre la base de données hors ligne et elle l'a été ALTER DATABASE <YourDatabase> SET OFFLINE
. Il n'y a eu aucune tentative de retour en arrière, c'est pourquoi il attendait indéfiniment. Dans votre cas, si vous vouliez restaurer des sessions qui avaient des verrous sur cette base de données, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
cela aurait probablement suffi si vous aviez déterminé initialement que la restauration était correcte.