脚本终止与数据库的所有连接(超过RESTRICTED_USER ROLLBACK)

我有一个开发数据库,​​经常从一个Visual Studio数据库项目(通过TFS自动构build)重新部署。

有时当我运行我的构build时,我得到这个错误:

ALTER DATABASE失败,因为锁不能放在数据库'MyDB'上。 稍后再试。
ALTER DATABASE语句失败。
不能删除数据库“MyDB”,因为它目前正在使用中。

我试过这个:

ALTER DATABASE MyDB SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE 

但我仍然不能删除数据库。 (我的猜测是大多数开发人员都有dbo访问权限。)

我可以手动运行SP_WHO,并开始查杀连接,但是我需要一种自动的方式在自动构build中做到这一点。 (虽然这次我的连接是唯一一个在我试图删除的分贝。)

有没有一个脚本,可以删除我的数据库,无论谁连接?

更新

对于MS SQL Server 2012及更高版本

 USE [master]; DECLARE @kill varchar(8000) = ''; SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), session_id) + ';' FROM sys.dm_exec_sessions WHERE database_id = db_id('MyDB') EXEC(@kill); 

对于MS SQL Server 2000,2005,2008

 USE master; DECLARE @kill varchar(8000); SET @kill = ''; SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), spid) + ';' FROM master..sysprocesses WHERE dbid = db_id('MyDB') EXEC(@kill); 
 USE master GO ALTER DATABASE database_name SET OFFLINE WITH ROLLBACK IMMEDIATE GO 

参考: http : //msdn.microsoft.com/en-us/library/bb522682%28v=sql.105%29.aspx

您可以通过执行以下操作获取SSMS提供的脚本:

  1. 右键单击SSMS中的数据库,然后select删除
  2. 在对话框中,选中“closures现有连接”checkbox。
  3. 点击对话框顶部的脚本button。

该脚本将如下所示:

 USE [master] GO ALTER DATABASE [YourDatabaseName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO USE [master] GO DROP DATABASE [YourDatabaseName] GO 

鲜为人知:GO sql语句可以取一个整数来重复上一个命令的次数。

所以如果你:

 ALTER DATABASE [DATABASENAME] SET SINGLE_USER GO 

然后:

 USE [DATABASENAME] GO 2000 

这会重复USE命令2000次,强制所有其他连接发生死锁,并获得单个连接的所有权。 (给你的查询窗口唯一的访问做你想做的。)

根据我的经验,使用SINGLE_USER可以帮助大部分时间,但是,我应该小心:在开始SINGLE_USER命令和完成时间之间,我经历过一段时间……显然,另一个“用户”已经获得了SINGLE_USER访问,不是我。 如果发生了这种情况,那么你需要重新访问数据库(在我的情况下,这是一个运行SQL数据库的软件的特定服务,在我之前获得了SINGLE_USER权限)。 我认为应该是最可靠的方式(不能担保,但是我将在未来的日子里进行testing)实际上是: – 停止可能干扰您访问的服务(如果有的话) – 使用上面的'kill'脚本来closures所有的连接 – 之后立即将数据库设置为single_user – 然后进行恢复

听上去怎么样 ?

马修的最高效的脚本更新为使用dm_exec_sessions DMV,replace弃用的sysprocesses系统表:

 USE [master]; GO DECLARE @Kill VARCHAR(8000) = ''; SELECT @Kill = @Kill + 'kill ' + CONVERT(VARCHAR(5), session_id) + ';' FROM sys.dm_exec_sessions WHERE database_id = DB_ID('<YourDB>'); EXEC sys.sp_executesql @Kill; 

替代使用WHILE循环(如果您想要执行每个执行任何其他操作):

 USE [master]; GO DECLARE @DatabaseID SMALLINT = DB_ID(N'<YourDB>'); DECLARE @SQL NVARCHAR(10); WHILE EXISTS ( SELECT 1 FROM sys.dm_exec_sessions WHERE database_id = @DatabaseID ) BEGIN; SET @SQL = ( SELECT TOP 1 N'kill ' + CAST(session_id AS NVARCHAR(5)) + ';' FROM sys.dm_exec_sessions WHERE database_id = @DatabaseID ); EXEC sys.sp_executesql @SQL; END; 

在杀人过程中你应该小心exception。 所以你可以使用这个脚本:

 USE master; GO DECLARE @kill varchar(max) = ''; SELECT @kill = @kill + 'BEGIN TRY KILL ' + CONVERT(varchar(5), spid) + ';' + ' END TRY BEGIN CATCH END CATCH ;' FROM master..sysprocesses EXEC (@kill) 

@AlexK写了一个很好的答案 。 我只想补充我的两分钱。 下面的代码完全基于@ AlexK的答案,区别在于你可以指定用户和自上次批处理执行以来的一段时间(注意代码使用sys.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) 

在这个例子中,只有最后一批执行超过1小时的用户usrDBTest的进程将被终止。

你可以这样使用Cursor

 USE master GO DECLARE @SQL AS VARCHAR(255) DECLARE @SPID AS SMALLINT DECLARE @Database AS VARCHAR(500) SET @Database = 'AdventureWorks2016CTP3' DECLARE Murderer CURSOR FOR SELECT spid FROM sys.sysprocesses WHERE DB_NAME(dbid) = @Database OPEN Murderer FETCH NEXT FROM Murderer INTO @SPID WHILE @@FETCH_STATUS = 0 BEGIN SET @SQL = 'Kill ' + CAST(@SPID AS VARCHAR(10)) + ';' EXEC (@SQL) PRINT ' Process ' + CAST(@SPID AS VARCHAR(10)) +' has been killed' FETCH NEXT FROM Murderer INTO @SPID END CLOSE Murderer DEALLOCATE Murderer 

我在这里写了关于这个: http : //www.pigeonsql.com/single-post/2016/12/13/Kill-all-connections-on-DB-by-Cursor

我已经用下面的简单代码成功testing过了

 USE [master] GO ALTER DATABASE [YourDatabaseName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO