SQL Server no puede eliminar la base de datos <dbname> porque está actualmente en uso ... pero no se muestran sesiones

72

Cuando intento descartar una base de datos, aparece el error "No se puede descartar la base de datos" dbname "porque está actualmente en uso". Sin embargo, cuando ejecuto sp_who2, definitivamente no hay sesiones conectadas a esta base de datos. También he configurado la base de datos a single_user mode with rollback immediate.

¿Por qué está pasando esto?

tuseau
fuente

Respuestas:

20

Asegúrese de que no tiene dependencias como instantáneas de base de datos en la base de datos que desea eliminar. Sin embargo, el mensaje de error sería diferente. ¿Estás seguro de que no hay ningún proceso oculto que se conecte a tu base de datos? Un buen enfoque sería ejecutar un script que mate todas las sesiones e inmediatamente después de cambiar el nombre de la base de datos a otro nombre y luego soltar la base de datos.

crear un cursor basado en esta selección:

  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')

problema dentro del cursor:

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

después de cerrar el cursor y desasignarlo:

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

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
yrushka
fuente
Gracias por el código, eso podría funcionar. Lo que no entiendo es, ¿qué es una sesión "oculta"? Pensé que sp_who y los otros metadatos (DMV) mostrarían todas las sesiones, de lo contrario, ¿de qué sirven?
tuseau
Sí, normalmente debería poder ver todos los activos / no activos a través de sp_who o consultar la tabla sysprocesses desde master db. Por oculto me refería a un proceso que se reconecta desde un servicio de aplicación. Salud.
yrushka
1
Esto es anticuado por múltiples razones: (1) uniones de estilo antiguo (2) vistas de compatibilidad con versiones anteriores (3) un cursor y SQL dinámico para ejecutar un montón de comandos KILL cuando un solo ALTER realizará (4) procedimientos obsoletos como sp_dboption.
Aaron Bertrand
1
Desafortunadamente, no creo que esto responda la pregunta: el interlocutor pregunta por qué sucede esto, no cómo resolverlo. La respuesta proporcionada funciona, pero todavía no sé qué me impide eliminar una base de datos. @AaronBertrand mencionó que "incluso el Explorador de objetos podría ser el culpable", lo que en realidad terminó siendo la razón de UNA de las bases de datos, pero ¿cómo podría decir que es seguro el Explorador de objetos?
LearnByReading
esto me da el error "No se puede usar KILL para matar tu propio proceso"
nuander
80

Una sesión conectada a otra base de datos puede tener una transacción abierta que también afecta a su base de datos: sp_who2 solo mostrará una base de datos. También podría ser algo tan simple como el Explorador de objetos o los Detalles del Explorador de objetos abiertos en SSMS, que nuevamente solo mostrarían una base de datos en sp_who2.

No te molestes en tratar de encontrar la sesión responsable; simplemente mátelos a todos con una declaración (y asegúrese de que no esté conectada su copia de SSMS, por ejemplo, otra ventana de consulta, Object Explorer, etc.):

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

Ahora podrá soltarlo y hacerlo utilizando DDL, no la interfaz de usuario:

DROP DATABASE dbname;
Aaron Bertrand
fuente
1
Gracias por su respuesta, esto funcionó. Pero solo estoy teniendo dificultades para vivir con esta solución: ¿por qué no puedo eliminar algunas bases de datos debido a este error? Tengo algunas bases de datos que no se han tocado durante un año y no hay ningún proceso o transacción ostensible que estén conectadas a ellas. ¿Podría darme algunos consejos para ayudarme a encontrar posibles servicios, transacciones o cualquier cosa que esté conectada a estas bases de datos?
LearnByReading
1
En realidad, todo lo que tenía que hacer era USE master, entonces DROP DATABASE dbname. Aparentemente, todo lo que se necesita es simplemente "usar" algo más, para liberar el db.
vapcguy
2
@vapcguy Eso solo es cierto si su ventana de consulta actual es la única conexión. Este no suele ser el caso (y es por eso que mis respuestas dicen "y asegúrese de que no esté conectada su copia de SSMS").
Aaron Bertrand
20

¿Cuál es su base de datos actual cuando emite el DROPcomando? Prueba esto:

use master
go
drop database mydb
go

También asegúrese de estar conectado como say no dboen la base de datos que desea soltar.

Gayo
fuente
Definitivamente estoy conectado con el maestro. No debería tener que estar conectado como sa para descartar una base de datos. Esto me parece un error: no muestra una sesión, o cree que hay una sesión en uso pero no la hay.
tuseau
3
Me quedé atrapado con esto: ¡intenté ejecutar el script de caída con el contexto establecido en la base de datos desde el símbolo del sistema sqlcmd! Doh
JonnyRaa
18

¿Qué tal simplemente ver lo que hace SSMS cuando usa la interfaz de usuario pero le dice que emita un script para la acción? Esto es lo que hace SSMS cuando hace clic derecho en la base de datos y selecciona Eliminar, luego marca la casilla para cerrar las conexiones existentes:

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
fuente
... suponiendo, por supuesto, que está bien revertir transacciones no confirmadas
swasheck
44
Estás descartando la base de datos, supongo que está bastante bien.
georgiosd
1
¡Esto funcionó para mí! :)
Leonardo Trimarchi
5

Me he enfrentado a esta situación muchas veces y a continuación es lo que hago:

Cuando los métodos obvios no funcionan ..... (como en su situación):

Encuentre el ID de la base de datos de sysdatabases

Luego ejecute: sp_lockeso mostrará todos los bloqueos en la instancia junto con spid y dbid.

Mata a los spids con el dbid que estás intentando desconectar o soltar.

Sin embargo, el proceso es un poco manual, se puede automatizar de la siguiente manera:

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
fuente
2

Encontré una respuesta realmente simple en StackOverflow que funcionó por primera vez para mí:

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

Aquí está el SQL de esa respuesta:

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
fuente