Repro
- Apri SSMS
Digitare quanto segue in una nuova finestra di query
use <YourDatabase>;
go
- Passare a Esplora oggetti (SSMS) e fare clic con il tasto destro su
<YourDatabase>
-> Tasks
->Take Offline
Aprire una seconda nuova finestra di query e digitare quanto segue:
use <YourDatabase>;
go
Ti verrà richiesto con il seguente messaggio:
Messaggio 952, livello 16, stato 1, riga 1
Database "TestDb1" è in transizione. Prova la dichiarazione più tardi.
Il motivo per cui ciò accade può essere trovato da una query diagnostica simile a quella seguente:
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;
Per quello che vale, non è necessario Esplora oggetti per riprodurre questo errore. Hai solo bisogno di una richiesta bloccata che sta tentando la stessa operazione (in questo caso, porta il database offline). Vedi lo screenshot seguente per i tre passaggi in T-SQL:
Ciò che molto probabilmente vedrai è che la sessione di Esplora oggetti viene bloccata da un'altra sessione (indicata da blocking_session_id
). La sessione Esplora oggetti tenterà di ottenere un blocco esclusivo ( X
) sul database. Nel caso della replica precedente, alla sessione Esplora oggetti è stato concesso un blocco degli aggiornamenti ( U
) e tentando di convertirlo in un blocco esclusivo ( X
). Aveva un wait_type di LCK_M_X
, bloccato dalla nostra sessione che era rappresentata dalla prima finestra della query ( use <YourDatabase>
prende un lock condiviso ( S
) sul database).
E quindi questo errore è nato da un'altra sessione che ha cercato di ottenere un blocco e questo messaggio di errore comporta la negazione di una sessione per ottenere l'accesso a un database che sta tentando di passare a uno stato diverso (in questo caso, lo stato online alla transizione offline).
Cosa dovresti fare la prossima volta?
Prima di tutto, non farti prendere dal panico e non iniziare a eliminare i database . È necessario adottare un approccio di risoluzione dei problemi (con una query diagnostica simile a quella sopra) per scoprire perché stai vedendo quello che stai vedendo. Con un messaggio del genere o quando qualcosa appare "bloccato", dovresti assumere automaticamente una mancanza di concorrenza e iniziare a scavare nel blocco ( sys.dm_tran_locks
è un buon inizio).
Come nota a margine, credo davvero che tu sia meglio scoprire la radice di un problema prima di intraprendere qualsiasi azione casuale. Non solo con questa operazione, ma vale per tutti i comportamenti che non ti aspetti. Sapendo cosa stava davvero causando il tuo problema, è ovvio che non era un grosso problema. Fondamentalmente avevi una catena di blocco e il blocco dei genitori era qualcosa che molto probabilmente avresti potuto emettere KILL
, o se era una richiesta di una sessione che non volevi, KILL
avresti potuto aspettare fino al completamento. Ad ogni modo, avresti avuto le conoscenze per prendere la decisione giusta e prudente dato il tuo particolare scenario (rollback o attendere il commit).
Un'altra cosa degna di nota, questo è uno dei motivi per cui scelgo sempre l'alternativa T-SQL anziché una GUI. Sai esattamente cosa stai eseguendo con T-SQL e cosa sta facendo SQL Server. Dopo tutto, hai emesso il comando esplicito. Quando si utilizza una GUI, l'attuale T-SQL sarà un'astrazione. In questo caso, ho esaminato il tentativo di Object Explorer bloccato di portare offline il database ed è stato ALTER DATABASE <YourDatabase> SET OFFLINE
. Non c'è stato alcun tentativo di rollback, motivo per cui è stato indefinitamente in attesa. Nel tuo caso, se volessi eseguire il rollback delle sessioni con blocchi su quel database, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
molto probabilmente ti basterebbe se avessi preso la decisione iniziale che il rollback andava bene.