web-dev-qa-db-fra.com

SQL Server ne peut pas supprimer la base de données <dbname> car elle est en cours d'utilisation ... mais aucune session ne s'affiche

Lorsque j'essaie de supprimer une base de données, j'obtiens l'erreur "Impossible de supprimer la base de données" nom_base "car elle est actuellement utilisée". Cependant, lorsque je lance sp_who2, il n'y a certainement aucune session connectée à cette base de données. J'ai également défini la base de données sur single_user mode with rollback immediate.

Pourquoi cela arrive-t-il?

81
tuseau

Assurez-vous que vous n'avez pas de dépendances comme des instantanés de base de données sur la base de données que vous souhaitez supprimer. Cependant, le message d'erreur se présenterait autrement. Êtes-vous sûr qu'aucun processus masqué ne se connecte à votre base de données? Une bonne approche serait d'exécuter un script qui tue toutes les sessions et immédiatement après renommer la base de données sous un autre nom, puis supprimer la base de données.

créer un curseur basé sur cette sélection:

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

problème à l'intérieur du curseur:

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

une fois le curseur fermé et désalloué:

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

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
22
yrushka

Une session connectée à une autre base de données peut avoir une transaction ouverte qui affecte également votre base de données - sp_who2 n'affichera qu'une seule base de données. Cela pourrait également être quelque chose d'aussi simple que l'explorateur d'objets ou les détails de l'explorateur d'objets ouverts dans SSMS, qui ne montreraient encore qu'une seule base de données dans sp_who2.

Ne vous embêtez pas à essayer de trouver la session qui est responsable; tuez-les tous avec une seule instruction (et assurez-vous que ce n'est pas votre copie de SSMS qui est connectée, par exemple une autre fenêtre de requête, l'Explorateur d'objets, etc.):

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

Maintenant, vous pourrez le supprimer et le faire en utilisant DDL, pas l'interface utilisateur:

DROP DATABASE dbname;
92
Aaron Bertrand

Quelle est votre base de données actuelle lorsque vous exécutez la commande DROP? Essaye ça:

use master
go
drop database mydb
go

Assurez-vous également que vous êtes connecté en tant que sa et non dbo sur la base de données que vous souhaitez supprimer.

20
Gaius

Que diriez-vous simplement de voir ce que fait SSMS lorsque vous utilisez l'interface utilisateur mais lui dites d'émettre un script pour l'action? Voici ce que fait SSMS lorsque vous cliquez avec le bouton droit sur la base de données et choisissez Supprimer, puis cochez la case pour fermer les connexions existantes:

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
18
Thiago Silva

J'ai fait face à cette situation à plusieurs reprises et voici ce que je fais:

Quand les méthodes évidentes ne fonctionnent pas ..... (comme dans votre situation):

Découvrez l'ID de la base de données dans sysdatabases.

Exécutez ensuite - sp_lock qui affichera tous les verrous de l'instance ainsi que spid et dbid.

Tuez les spids avec la dbid que vous essayez de déconnecter ou de supprimer.

Bien que le processus soit un peu manuel, il peut être automatisé comme ci-dessous:

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
5
Kin Shah

J'ai trouvé une réponse très simple sur StackOverflow qui a fonctionné pour la première fois pour moi:

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

Voici le SQL de cette réponse:

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)
3
Adrian Carr