我有一个经常从Visual Studio数据库项目重新部署的开发数据库(通过TFS自动构建)。
有时当我运行我的构建时,我会得到这个错误:
ALTER DATABASE failed because a lock could not be placed on database 'MyDB'. Try again later.
ALTER DATABASE statement failed.
Cannot drop database "MyDB" because it is currently in use.
我试了一下:
ALTER DATABASE MyDB SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE
但我仍然无法删除数据库。(我猜大多数开发人员都有dbo访问权限。)
我可以手动运行SP_WHO并开始终止连接,但我需要在自动构建中自动执行此操作。(虽然这次我的连接是数据库中唯一一个我试图放弃的连接。)
是否有一个脚本可以删除我的数据库,而不管连接的是谁?
SELECT
spid,
sp.[status],
loginame [Login],
hostname,
blocked BlkBy,
sd.name DBName,
cmd Command,
cpu CPUTime,
memusage Memory,
physical_io DiskIO,
lastwaittype LastWaitType,
[program_name] ProgramName,
last_batch LastBatch,
login_time LoginTime,
'kill ' + CAST(spid as varchar(10)) as 'Kill Command'
FROM master.dbo.sysprocesses sp
JOIN master.dbo.sysdatabases sd ON sp.dbid = sd.dbid
WHERE sd.name NOT IN ('master', 'model', 'msdb')
--AND sd.name = 'db_name'
--AND hostname like 'hostname1%'
--AND loginame like 'username1%'
ORDER BY spid
/* If a service connects continously. You can automatically execute kill process then run your script:
DECLARE @sqlcommand nvarchar (500)
SELECT @sqlcommand = 'kill ' + CAST(spid as varchar(10))
FROM master.dbo.sysprocesses sp
JOIN master.dbo.sysdatabases sd ON sp.dbid = sd.dbid
WHERE sd.name NOT IN ('master', 'model', 'msdb')
--AND sd.name = 'db_name'
--AND hostname like 'hostname1%'
--AND loginame like 'username1%'
--SELECT @sqlcommand
EXEC sp_executesql @sqlcommand
*/
@AlexK写了一个很棒的答案。我只是想补充我的意见。下面的代码完全基于@AlexK的回答,不同之处在于,您可以指定用户和自最后一批执行以来的时间(注意,代码使用sys. exe。Dm_exec_sessions代替master..sysprocess):
DECLARE @kill varchar(8000);
set @kill =''
select @kill = @kill + 'kill ' + CONVERT(varchar(5), session_id) + ';' from sys.dm_exec_sessions
where login_name = 'usrDBTest'
and datediff(hh,login_time,getdate()) > 1
--and session_id in (311,266)
exec(@kill)
在这个例子中,只有用户usrDBTest在1小时前执行的进程会被杀死。
公认的答案有一个缺点,即它没有考虑到数据库可能被正在执行查询的连接所锁定,该查询涉及到所连接的数据库以外的数据库中的表。
如果服务器实例有多个数据库,并且查询直接或间接(例如通过同义词)使用多个数据库中的表等,就会出现这种情况。
因此,我发现有时最好使用syslockinfo来查找要删除的连接。
因此,我的建议是使用AlexK给出的接受答案的以下变体:
USE [master];
DECLARE @kill varchar(8000) = '';
SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), req_spid) + ';'
FROM master.dbo.syslockinfo
WHERE rsc_type = 2
AND rsc_dbid = db_id('MyDB')
EXEC(@kill);