SQL Server kann die Datenbank <Datenbankname> nicht löschen, da sie derzeit verwendet wird. Es werden jedoch keine Sitzungen angezeigt

72

Wenn ich versuche, eine Datenbank zu löschen, erhalte ich die Fehlermeldung "Datenbank" dbname "kann nicht gelöscht werden, da sie derzeit verwendet wird". Wenn ich jedoch starte sp_who2, sind definitiv keine Sitzungen mit dieser Datenbank verbunden. Ich habe auch die Datenbank auf eingestellt single_user mode with rollback immediate.

Warum passiert dies?

Tuseau
quelle

Antworten:

20

Stellen Sie sicher, dass Sie keine Abhängigkeiten wie Datenbank-Snapshots von der Datenbank haben, die Sie entfernen möchten. Die Fehlermeldung würde jedoch anders aussehen. Sind Sie sicher, dass es keinen versteckten Prozess gibt, der eine Verbindung zu Ihrer Datenbank herstellt? Ein guter Ansatz wäre, ein Skript auszuführen, das alle Sitzungen beendet und die Datenbank sofort nach dem Umbenennen in einen anderen Namen umbenennt und die Datenbank dann löscht.

Erstellen Sie einen Cursor basierend auf dieser Auswahl:

  select  d.name , convert (smallint, req_spid) As spid
      from master.dbo.syslockinfo l, 
           master.dbo.spt_values v,
           master.dbo.spt_values x, 
           master.dbo.spt_values u, 
           master.dbo.sysdatabases d
      where   l.rsc_type = v.number 
      and v.type = 'LR' 
      and l.req_status = x.number 
      and x.type = 'LS' 
      and l.req_mode + 1 = u.number
      and u.type = 'L' 
      and l.rsc_dbid = d.dbid 
      and rsc_dbid = (select top 1 dbid from 
                      master..sysdatabases 
                      where name like 'my_db')

Ausgabe innerhalb des Cursors:

SET @kill_process =  'KILL ' + @spid      
            EXEC master.dbo.sp_executesql @kill_process
                   PRINT 'killed spid : '+ @spid

Nachdem der Cursor geschlossen und freigegeben wurde:

sp_dboption 'my_db', 'single user', 'TRUE'

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
yrushka
quelle
Danke für den Code - das könnte funktionieren. Was ich nicht verstehe ist, was ist eine "versteckte" Sitzung? Ich hätte gedacht, sp_who und die anderen Metadaten (DMVs) würden alle Sitzungen anzeigen.
Tuseau
Ja, normalerweise sollten Sie in der Lage sein, alle aktiven / nicht aktiven Daten über sp_who zu sehen oder die Sysprocesses-Tabelle von der Master-Datenbank abzufragen. Mit versteckt meinte ich einen Prozess, der sich wieder von einem Anwendungsdienst verbindet. Prost.
Yrushka
1
Dies ist aus mehreren Gründen veraltet: (1) Joins im alten Stil (2) Abwärtskompatibilitätsansichten (3) Ein Cursor und dynamisches SQL, um eine Reihe von KILL-Befehlen auszuführen, wenn ein einzelnes ALTER (4) veraltete Prozeduren wie sp_dboption ausführt.
Aaron Bertrand
1
Leider glaube ich nicht, dass dies die Frage beantwortet - der Fragesteller fragt, warum dies geschieht, und nicht, wie es zu lösen ist. Die Antwort funktioniert, aber ich weiß immer noch nicht, was mich davon abhält, eine Datenbank zu löschen. @AaronBertrand erwähnte, dass "sogar der Objekt-Explorer der Schuldige sein könnte", was letztendlich der Grund für EINE der Datenbanken war, aber wie konnte ich sicher sagen, dass es sich um den Objekt-Explorer handelte?
LearnByReading
dies gibt mir den
fehler
80

Eine Sitzung, die mit einer anderen Datenbank verbunden ist, hat möglicherweise eine offene Transaktion, die sich auch auf Ihre Datenbank auswirkt - sp_who2 zeigt nur eine Datenbank an. Es könnte auch so einfach sein, dass der Objekt-Explorer oder die Objekt-Explorer-Details in SSMS geöffnet werden, wodurch wiederum nur eine Datenbank in sp_who2 angezeigt wird.

Versuchen Sie nicht , die verantwortliche Sitzung zu finden . Töte sie einfach alle mit einer Anweisung (und stelle sicher, dass nicht deine SSMS-Kopie verbunden ist, z. B. ein anderes Abfragefenster, Objekt-Explorer usw.):

USE master;
GO
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

Jetzt können Sie es löschen und dies mit DDL und nicht mit der Benutzeroberfläche tun:

DROP DATABASE dbname;
Aaron Bertrand
quelle
1
Vielen Dank für Ihre Antwort, das hat funktioniert. Aber ich habe nur Schwierigkeiten, mit dieser Lösung zu leben: Warum kann ich aufgrund dieses Fehlers einige Datenbanken nicht löschen? Ich habe einige Datenbanken, die seit einem Jahr nicht mehr berührt wurden, und es gibt keine Prozesse oder angeblichen Transaktionen, die damit verbunden sind. Könnten Sie mir einige Hinweise geben, die mir bei der Suche nach potenziellen Diensten, Transaktionen oder allem, was mit diesen Datenbanken verbunden ist, helfen?
LearnByReading
1
Eigentlich musste ich USE masterdann nur noch DROP DATABASE dbname. Anscheinend ist alles, was benötigt wird, etwas anderes zu "benutzen", um die Datenbank freizugeben.
Vapcguy
2
@vapcguy Das ist nur wahr, wenn Ihr aktuelles Abfragefenster die einzige Verbindung ist. Dies ist normalerweise nicht der Fall (und aus diesem Grund heißt es in meinen Antworten "und stellen Sie sicher, dass nicht Ihre Kopie von SSMS verbunden ist").
Aaron Bertrand
20

Was ist Ihre aktuelle Datenbank, wenn Sie den DROPBefehl ausgeben ? Versuche dies:

use master
go
drop database mydb
go

Stellen Sie außerdem sicher, dass Sie mit der Datenbank verbunden sind saund nicht dbomit der Datenbank, die Sie löschen möchten.

Gaius
quelle
Ich bin definitiv mit dem Meister verbunden. Ich sollte nicht als sa verbunden sein müssen, um eine Datenbank zu löschen. Dies sieht für mich nach einem Fehler aus - es wird keine Sitzung angezeigt oder es wird angenommen, dass eine Sitzung verwendet wird, dies ist jedoch nicht der Fall.
Tuseau
3
Ich habe mich soeben damit abgefunden - ich habe versucht, das Ablageskript mit dem auf die Datenbank festgelegten Kontext über die sqlcmd-Eingabeaufforderung auszuführen! Doh
JonnyRaa
18

Wie wäre es, wenn Sie nur sehen, was SSMS tut, wenn Sie die Benutzeroberfläche verwenden, diese aber anweisen, ein Skript für die Aktion auszugeben? So funktioniert SSMS, wenn Sie mit der rechten Maustaste auf die Datenbank klicken und Löschen auswählen und dann das Kontrollkästchen aktivieren, um vorhandene Verbindungen zu schließen:

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'yourdbname'
GO

USE [master]
GO
ALTER DATABASE [yourdbname] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

USE [master]
GO

DROP DATABASE [yourdbname]
GO
Thiago Silva
quelle
... vorausgesetzt, es ist in Ordnung, nicht
festgeschriebene
4
Sie löschen die Datenbank, ich würde davon ausgehen, dass es ganz in Ordnung ist.
Georgiosd
1
Das hat bei mir funktioniert! :)
Leonardo Trimarchi
5

Ich habe mich dieser Situation viele Male gestellt und mache folgendes:

Wenn offensichtliche Methoden nicht funktionieren ... (genau wie in Ihrer Situation):

Ermitteln Sie die Datenbank-ID aus sysdatabases.

Dann ausführen - sp_lockdas zeigt alle Sperren für die Instanz zusammen mit spid und dbid.

Töten Sie die Spids mit dem dbid, das Sie offline schalten oder löschen möchten.

Obwohl der Prozess ein bisschen manuell ist, kann er wie folgt automatisiert werden:

IF OBJECT_ID('tempdb.dbo.#temp', 'U') IS NOT NULL
  DROP TABLE #temp;
create table #temp (spid int
                , dbid int
                ,ObjId bigint
                , IndId bigint
                ,Type varchar(5)
                ,resource varchar(max)
                ,Mode varchar(5)
                ,status varchar(10));
declare @dbid int
select @dbid =DB_ID(db_name())

insert into #temp
exec sp_lock

select * from #temp
where dbid = @dbid
Kin Shah
quelle
2

Auf StackOverflow wurde eine wirklich einfache Antwort gefunden, die bei mir zum ersten Mal funktioniert hat:

https://stackoverflow.com/a/7469167/261405

Hier ist die SQL aus dieser Antwort:

DECLARE @DatabaseName nvarchar(50)
SET @DatabaseName = N'YOUR_DABASE_NAME'

DECLARE @SQL varchar(max)

SELECT @SQL = COALESCE(@SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(@DatabaseName) AND SPId <> @@SPId

--Use this to see results
SELECT @SQL 
--Uncomment this to run it
--EXEC(@SQL)
Adrian Carr
quelle