it-swarm.it

SQL Server Impossibile eliminare il database <dbname> perché è attualmente in uso ... ma nessuna sessione visualizzata

Quando provo a eliminare un database, viene visualizzato l'errore "Impossibile eliminare il database" dbname "perché è attualmente in uso". Tuttavia, quando eseguo sp_who2, sicuramente non ci sono sessioni connesse a questo database. Ho anche impostato il database su single_user mode with rollback immediate.

Perché sta succedendo?

81
tuseau

Assicurati di non avere dipendenze come gli snapshot del database sul db che desideri rimuovere. Tuttavia, il messaggio di errore apparirebbe diversamente. Sei sicuro che non ci siano processi nascosti che si collegano al tuo database? Un buon approccio sarebbe quello di eseguire uno script che uccide tutte le sessioni e subito dopo rinominare il database con un altro nome e quindi rilasciare il database.

crea un cursore basato su questa selezione:

  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 all'interno del cursore:

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

dopo che il cursore è chiuso e deallocato:

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

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
22
yrushka

Una sessione connessa a un altro database potrebbe avere una transazione aperta che influisce anche sul tuo database - sp_who2 mostrerà solo un database. Potrebbe anche essere qualcosa di semplice come Esplora oggetti o Dettagli Esplora oggetti aperti in SSMS, che mostrerebbe nuovamente un solo database in sp_who2.

Non preoccuparti di provare a trovare la sessione responsabile; uccidili tutti con un'istruzione (e assicurati che non sia la tua copia di SSMS a essere connessa, ad esempio un'altra finestra di query, Esplora oggetti, ecc.):

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

Ora sarai in grado di rilasciarlo e farlo utilizzando DDL, non l'interfaccia utente:

DROP DATABASE dbname;
92
Aaron Bertrand

Qual è il tuo database attuale quando emetti il ​​comando DROP? Prova questo:

use master
go
drop database mydb
go

Assicurati anche di essere connesso come sa e non dbo su qualsiasi database che desideri eliminare.

20
Gaius

Che ne dici di vedere cosa fa SSMS quando usi l'interfaccia utente ma gli dici di emettere uno script per l'azione? Ecco cosa fa SSMS quando fai clic con il pulsante destro del mouse sul DB e scegli Elimina, quindi seleziona la casella per chiudere le connessioni esistenti:

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

Ho affrontato questa situazione molte volte e di seguito è quello che faccio:

Quando i metodi ovvi non funzionano ..... (proprio come nella tua situazione):

Scopri l'ID del database dai database di sistema.

Quindi eseguire - sp_lock che mostrerà tutti i blocchi sull'istanza insieme a spid e dbid.

Uccidi gli spid con il dbid che stai provando a disconnettere o rilasciare.

Tuttavia, il processo è un po 'manuale, può essere automatizzato come di seguito:

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

Ho trovato una risposta davvero semplice su StackOverflow che ha funzionato per la prima volta per me:

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

Ecco l'SQL da quella risposta:

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