Ich habe eine Entwicklungsdatenbank, die häufig aus einem Visual Studio-Datenbankprojekt (über ein TFS Auto Build) erneut bereitgestellt wird.
Manchmal, wenn ich meinen Build ausführe, wird folgende Fehlermeldung angezeigt:
ALTER DATABASE failed because a lock could not be placed on database 'MyDB'. Try again later.
ALTER DATABASE statement failed.
Cannot drop database "MyDB" because it is currently in use.
Ich habe es versucht:
ALTER DATABASE MyDB SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE
aber ich kann die Datenbank immer noch nicht löschen. (Ich vermute, dass die meisten Entwickler dbo
Zugriff haben.)
Ich kann Verbindungen manuell ausführen SP_WHO
und beenden, aber ich benötige eine automatische Methode, um dies im automatischen Build zu tun. (Obwohl diesmal meine Verbindung die einzige auf der Datenbank ist, die ich zu trennen versuche.)
Gibt es ein Skript, mit dem meine Datenbank gelöscht werden kann, unabhängig davon, wer verbunden ist?
kill
Aussagen zusammenzufassen. Ich würde einen Cursor verwenden, um jeden Prozess abzubrechen, was natürlich überhaupt nicht effizient ist. Die in dieser Antwort verwendete Technik ist brillant.USE [Master]
Ref: http://msdn.microsoft.com/en-us/library/bb522682%28v=sql.105%29.aspx
quelle
USE master
das der Schlüssel. Ich habe versucht, die Datenbank zu löschen, während ich mit ihr verbunden war (Duh!). Vielen Dank!SET OFFLINE
, müssen Sie die Datenbankdateien manuell löschen.alter database YourDatabaseName set SINGLE_USER with rollback immediate
besser? Wenn Sie es aufOFFLINE
(wie @mattalxndr angibt) setzen, bleiben die Dateien auf der Festplatte, aberSINGLE_USER
Ihre Verbindung bleibt die einzige unddrop database YourDatabaseName
die Dateien werden trotzdem entfernt.set offline
können Sieset online
Probleme verursachen, um das Problem mit den verbleibenden Dateien zu vermeiden (ja, es besteht die Möglichkeit einer Racebedingung).Sie können das von SSMS bereitgestellte Skript wie folgt abrufen:
Das Skript sieht ungefähr so aus:
quelle
Wenig bekannt: Die GO-SQL-Anweisung kann eine Ganzzahl für die Häufigkeit verwenden, mit der der vorherige Befehl wiederholt wird.
Also, wenn Sie:
Dann:
Dadurch wird der USE-Befehl 2000 Mal wiederholt, ein Deadlock für alle anderen Verbindungen erzwungen und der Besitz der einzelnen Verbindung übernommen. (Geben Sie Ihrem Abfragefenster den alleinigen Zugriff, um zu tun, was Sie möchten.)
quelle
Meiner Erfahrung nach hilft die Verwendung von SINGLE_USER meistens, aber man sollte vorsichtig sein: Ich habe Gelegenheiten erlebt, in denen zwischen dem Start des Befehls SINGLE_USER und dem Zeitpunkt, zu dem er beendet ist ... anscheinend ein anderer 'Benutzer' die erhalten hat SINGLE_USER Zugriff, nicht ich. In diesem Fall haben Sie es schwer, den Zugriff auf die Datenbank wiederherzustellen (in meinem Fall war es ein bestimmter Dienst, der für eine Software mit SQL-Datenbanken ausgeführt wurde, die vor mir den Zugriff auf SINGLE_USER erhalten hat). Was meiner Meinung nach der zuverlässigste Weg sein sollte (kann nicht dafür bürgen, aber ich werde ihn in den kommenden Tagen testen), ist tatsächlich:
- Stoppen Sie Dienste, die Ihren Zugriff beeinträchtigen können (falls vorhanden)
- Verwenden Sie das obige 'kill'-Skript, um alle Verbindungen zu schließen
- Setzen Sie die Datenbank unmittelbar danach auf single_user
- und führen Sie dann die Wiederherstellung durch
quelle
Matthews äußerst effizientes Skript wurde aktualisiert, um die DMV dm_exec_sessions zu verwenden, und ersetzt die veraltete Systemtabelle sysprocesses:
Alternative Verwendung der WHILE-Schleife (wenn Sie andere Operationen pro Ausführung verarbeiten möchten):
quelle
Die akzeptierte Antwort hat den Nachteil, dass nicht berücksichtigt wird, dass eine Datenbank durch eine Verbindung gesperrt werden kann, die eine Abfrage ausführt, die Tabellen in einer anderen als der mit ihr verbundenen Datenbank enthält.
Dies kann der Fall sein, wenn die Serverinstanz mehr als eine Datenbank hat und die Abfrage direkt oder indirekt (z. B. über Synonyme) Tabellen in mehr als einer Datenbank usw. verwendet.
Ich finde daher, dass es manchmal besser ist, syslockinfo zu verwenden, um die Verbindungen zu finden, die getötet werden sollen.
Mein Vorschlag wäre daher, die folgende Variante der akzeptierten Antwort von AlexK zu verwenden:
quelle
sys.dm_tran_locks
Tabelle persönlich alssyslockinfo
veraltet verwende, möchten Sie möglicherweise auch Ihre aktuelle @@ SPID für alle Fälle ausschließen.Sie sollten beim Töten auf Ausnahmen achten. Sie können dieses Skript also verwenden:
quelle
@AlexK hat eine großartige Antwort geschrieben . Ich möchte nur meine zwei Cent hinzufügen. Der folgende Code basiert vollständig auf der Antwort von @ AlexK. Der Unterschied besteht darin, dass Sie den Benutzer und eine Zeit seit der Ausführung des letzten Stapels angeben können (beachten Sie, dass der Code sys.dm_exec_sessions anstelle von master..sysprocess verwendet):
In diesem Beispiel wird nur der Prozess des Benutzers usrDBTest beendet, bei dem der letzte Stapel vor mehr als einer Stunde ausgeführt wurde.
quelle
Sie können den Cursor folgendermaßen verwenden :
Ich habe darüber in meinem Blog hier geschrieben: http://www.pigeonsql.com/single-post/2016/12/13/Kill-all-connections-on-DB-by-Cursor
quelle
quelle
Ich habe erfolgreich mit einfachem Code unten getestet
quelle
set SINGLE_USER
wenn bereits eine einzige aktive Verbindung bestand.