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


72

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

Perché sta succedendo?

Risposte:


20

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 

Grazie per il codice - potrebbe funzionare. Quello che non capisco è, che cos'è una sessione "nascosta"? Avrei pensato che sp_who e gli altri metadati (DMV) avrebbero mostrato tutte le sessioni, altrimenti che uso hanno?
tuseau

Sì, normalmente dovresti essere in grado di vedere tutto attivo / non attivo tramite sp_who o interrogando la tabella sysprocesses dal master db. Per nascosto intendevo un processo che si riconnette da un servizio applicativo. Saluti.
yrushka,

1
Questo è antiquato per diversi motivi: (1) join di vecchio stile (2) visualizzazioni di compatibilità con le versioni precedenti (3) un cursore e SQL dinamico per eseguire un gruppo di comandi KILL quando un singolo ALTER eseguirà (4) procedure obsolete come sp_dboption.
Aaron Bertrand

1
Sfortunatamente non penso che questo risponda alla domanda: l'interrogante si sta chiedendo perché questo accada, non come risolverlo. La risposta fornita funziona, ma non so ancora cosa mi impedisce di eliminare un database. @AaronBertrand ha menzionato "anche Object Explorer potrebbe essere il colpevole" che in realtà è stato il motivo di UNO dei database, ma come potrei dire che era Explorer oggetti?
LearnByLeggi del

questo mi dà l'errore "Impossibile usare KILL per
terminare il

80

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 cercare la sessione responsabile; uccidili tutti con un'istruzione (e assicurati che non sia connessa la tua copia di SSMS, 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;

1
Grazie per la tua risposta, ha funzionato. Ma ho solo difficoltà a convivere con questa soluzione: perché non riesco a eliminare alcuni database a causa di questo errore? Ho alcuni database che non sono stati toccati per un anno e non vi è alcun processo o transazione apparente ad essi collegati. Potresti darmi qualche suggerimento per aiutarmi a trovare potenziali servizi o transazioni o qualsiasi cosa sia collegata a questi database?
LearnByLeggi del

1
In realtà, tutto ciò che dovevo fare era USE master, quindi DROP DATABASE dbname. Apparentemente tutto ciò che serve è semplicemente "usare" qualcos'altro, per rilasciare il db.
vapcguy,

2
@vapcguy Questo è vero solo se la finestra della query corrente è l'unica connessione. Questo in genere non è il caso (ed è per questo che le mie risposte indicano "e assicurati che non sia la tua copia di SSMS ad essere connessa").
Aaron Bertrand

20

Qual è il tuo database attuale quando emetti il DROPcomando? Prova questo:

use master
go
drop database mydb
go

Assicurati anche di essere connesso come sae non dbosu qualsiasi database che desideri eliminare.


Sono sicuramente collegato al maestro. Non dovrei essere collegato come sa per eliminare un database. Questo mi sembra un bug: non mostra una sessione o pensa che ci sia una sessione in uso ma non lo è.
tuseau

3
Sono appena stato sorpreso da questo: ho provato a eseguire lo script di rilascio con il contesto impostato sul database dal prompt sqlcmd! Doh
JonnyRaa,

18

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

... supponendo, ovviamente, che sia OK ripristinare le transazioni non
confermate

4
Stai lasciando cadere il database, suppongo che sia abbastanza bene.
Georgiosd,

1
Questo ha funzionato per me! :)
Leonardo Trimarchi,

5

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 esegui - sp_lockquesto 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

2

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.