Při pokusu o vyřazení databáze se zobrazí chyba „Nelze zrušit databázi“ dbname ”, protože se právě používá. Když však spustím sp_who2
, k této databázi rozhodně nejsou žádné relace. Také jsem nastavil databázi na single_user mode with rollback immediate
.
Proč se toto děje?
Ujistěte se, že na db, který chcete odebrat, nemáte závislosti, jako jsou databázové snímky. Přesto by chybová zpráva vypadala jinak. Jste si jisti, že k vaší databázi není žádný skrytý proces? Dobrým přístupem by bylo spuštění skriptu, který zabije všechny relace a ihned po přejmenování databáze na jiné jméno a poté přetažení databáze.
vytvořte kurzor na základě tohoto výběru:
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')
vydání uvnitř kurzoru:
SET @kill_process = 'KILL ' + @spid
EXEC master.dbo.sp_executesql @kill_process
PRINT 'killed spid : '+ @spid
po uzavření kurzoru a uvolnění:
sp_dboption 'my_db', 'single user', 'TRUE'
go
sp_renamedb 'my_db', 'my_db_old'
go
DROP DATABASE MY_DB_OLD
Relace připojená k jiné databázi může mít otevřenou transakci, která také ovlivní vaši databázi - sp_who2 zobrazí pouze jednu databázi. Mohlo by to být také něco tak jednoduchého jako Object Explorer nebo Object Explorer Details otevřené v SSMS, které by znovu zobrazilo pouze jednu databázi v sp_who2.
Neobtěžujte se pokusit najít relaci, která je zodpovědná; prostě je všechny zabijte jedním příkazem (a ujistěte se, že to není vaše kopie SSMS, která je připojena, např. jiné okno dotazu, Průzkumník objektů atd.):
USE master;
GO
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
Nyní to budete moci zrušit a udělat to pomocí DDL, nikoli UI:
DROP DATABASE dbname;
Jaká je vaše aktuální databáze, když zadáte příkaz DROP
? Zkuste to:
use master
go
drop database mydb
go
Také se ujistěte, že jste připojeni jako sa
a ne dbo
do kterékoli databáze, kterou chcete zahodit.
Co takhle vidět, co SSMS dělá, když používáte UI, ale řekněte mu, aby vydal akci pro akci? Zde je to, co SSMS dělá, když kliknete pravým tlačítkem na DB a vyberete Odstranit, pak zaškrtnutím políčka uzavřete existující připojení:
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
Mnohokrát jsem čelil této situaci:
Když zřejmé metody nefungují ..... (stejně jako ve vaší situaci):
Vyhledejte ID databáze ze sysdatabases.
Poté spusťte - sp_lock
, které zobrazí všechny zámky v instanci spolu se spid a dbid.
Zabijte spids pomocí dbid, které se pokoušíte offline nebo upustit.
Přestože je tento proces trochu manuální, lze jej automatizovat takto:
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
Na StackOverflow jsem našel opravdu jednoduchou odpověď, která mi pracovala poprvé:
https://stackoverflow.com/a/7469167/261405
Zde je SQL z této odpovědi:
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)