Repro
- Öffnen Sie SSMS
Geben Sie Folgendes in ein neues Abfragefenster ein
use <YourDatabase>;
go
- Gehen Sie zum Objekt-Explorer (SSMS) und klicken Sie mit der rechten Maustaste auf
<YourDatabase>
-> Tasks
->Take Offline
Öffnen Sie ein zweites neues Abfragefenster und geben Sie Folgendes ein:
use <YourDatabase>;
go
Sie werden mit der folgenden Meldung aufgefordert:
Nachricht 952, Ebene 16,
Status 1, Zeile 1 Die Datenbank 'TestDb1' befindet sich im Übergang. Versuchen Sie die Aussage später.
Der Grund dafür ist in einer ähnlichen Diagnoseabfrage wie der folgenden zu finden:
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;
Für diesen Zweck benötigen Sie den Objekt-Explorer nicht, um diesen Fehler zu reproduzieren. Sie benötigen lediglich eine blockierte Anforderung, die denselben Vorgang versucht (in diesem Fall schalten Sie die Datenbank offline). Im folgenden Screenshot sind die drei Schritte in T-SQL dargestellt:
Was Sie höchstwahrscheinlich sehen werden, ist, dass Ihre Objekt-Explorer-Sitzung von einer anderen Sitzung blockiert wird (angezeigt durch blocking_session_id
). Diese Objekt-Explorer-Sitzung versucht, eine exklusive Sperre ( X
) für die Datenbank zu erhalten. Im Fall des obigen Repros wurde der Objekt-Explorer-Sitzung eine Aktualisierungssperre ( U
) gewährt und versucht, in eine exklusive Sperre ( X
) zu konvertieren . Es hatte einen wait_type von LCK_M_X
, der von unserer Sitzung blockiert wurde und durch das erste Abfragefenster dargestellt wurde (das use <YourDatabase>
eine gemeinsame Sperre ( S
) für die Datenbank abruft ).
Und dann kam dieser Fehler von einer weiteren Sitzung, die versuchte, eine Sperre zu erhalten, und diese Fehlermeldung führte dazu, dass eine Sitzung verweigert wurde, um Zugriff auf eine Datenbank zu erhalten, die versucht, in einen anderen Status überzugehen (in diesem Fall den Online-Status) zum Offline-Übergang).
Was solltest du das nächste Mal tun?
Zunächst einmal keine Panik und keine Datenbanken löschen . Sie müssen eine Fehlerbehebung durchführen (mit einer ähnlichen Diagnoseabfrage wie der oben genannten), um herauszufinden, warum Sie sehen, was Sie sehen. Bei einer solchen Nachricht oder wenn etwas "hängen sys.dm_tran_locks
bleibt ", sollten Sie automatisch einen Mangel an Parallelität annehmen und sich mit dem Blockieren befassen (dies ist ein guter Anfang).
Als Randnotiz glaube ich wirklich, dass Sie am besten die Wurzel eines Problems herausfinden sollten, bevor Sie zufällige Maßnahmen ergreifen. Nicht nur bei dieser Operation, sondern bei allen Verhaltensweisen, die Sie nicht erwarten. Wenn Sie wissen, was Ihr Problem wirklich verursacht hat, ist es offensichtlich keine große Sache. Sie hatten im Grunde eine Blockierungskette, und der übergeordnete Blocker war etwas, das Sie höchstwahrscheinlich gerade hätten aktivieren können KILL
, oder wenn es sich um eine Sitzungsanforderung handelte, die Sie nicht wollten, hätten KILL
Sie warten können, bis sie abgeschlossen war. In jedem Fall hätten Sie das Wissen gehabt, die richtige und umsichtige Entscheidung in Ihrem speziellen Szenario zu treffen (Rollback oder Warten auf Commit).
Eine andere erwähnenswerte Sache, dies ist einer der Gründe, warum ich mich immer für die T-SQL-Alternative anstelle einer GUI entscheide. Sie wissen genau, was Sie mit T-SQL ausführen und was SQL Server tut. Immerhin haben Sie den expliziten Befehl ausgegeben. Wenn Sie eine GUI verwenden, wird das eigentliche T-SQL eine Abstraktion sein. In diesem Fall habe ich mir den Versuch des blockierten Objekt-Explorers angesehen, die Datenbank offline zu schalten ALTER DATABASE <YourDatabase> SET OFFLINE
. Es gab keinen Versuch, einen Rollback durchzuführen, weshalb auf unbestimmte Zeit gewartet wurde. In Ihrem Fall, wenn Sie Sitzungen mit Sperren für diese Datenbank zurücksetzen wollten, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
hätte dies höchstwahrscheinlich ausgereicht, wenn Sie die anfängliche Feststellung getroffen hätten, dass das Zurücksetzen in Ordnung ist.