题
我想修改以下内容,因为它似乎不会杀死进程 - 我认为它应该断开用户连接(这是一样的吗?)。我希望能够终止特定数据库的所有进程 - 如何修改以下内容:
create procedure [dbo].[sp_killusers](@database varchar(30))
as
----------------------------------------------------
-- * Created By David Wiseman, Updated 19/11/2006
-- * http://www.wisesoft.co.uk
-- * This procedure takes the name of a database as input
-- * and uses the kill statment to disconnect them from
-- * the database.
-- * PLEASE USE WITH CAUTION!!
-- * Usage:
-- * exec sp_killusers 'databasename'
----------------------------------------------------
set nocount on
declare @spid int
declare @killstatement nvarchar(10)
-- Declare a cursor to select the users connected to the specified database
declare c1 cursor for select request_session_id
from sys.dm_tran_locks
where resource_type='DATABASE'
AND DB_NAME(resource_database_id) = @database
open c1
fetch next from c1 into @spid
-- for each spid...
while @@FETCH_STATUS = 0
begin
-- Don't kill the connection of the user executing this statement
IF @@SPID <> @spid
begin
-- Construct dynamic sql to kill spid
set @killstatement = 'KILL ' + cast(@spid as varchar(3))
exec sp_executesql @killstatement
-- Print killed spid
print @spid
end
fetch next from c1 into @spid
end
-- Clean up
close c1
deallocate c1
更新
上面的方法不起作用,即它不会终止该进程。
它不会杀死该进程。我查看活动监视器,它仍然显示该过程仍在继续,我可以看到我的查询仍在查询窗口中工作。当我进行“杀死53”时,查询在查询窗口中停止,并且该过程从活动监视器中消失了!所以 thkill 有效,但这个程序不起作用,为什么?
解决方案
我熟悉这个脚本。它会杀死所有正在使用数据库的SPID,是的。您需要在正确的权限下运行它 - 不只是任何用户都可以杀死SPID。
此外,您可能有应用程序尝试维护与数据库的持久连接,因此可能会在您终止其SPID后立即重新连接。
其他提示
您是否只是想停止对特定数据库的所有活动,以便对其进行一些维护?
如果是这样,您可以执行以下操作:
ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
这将终止访问数据库的所有其他SPID,并将数据库置于单用户模式。然后执行维护操作,然后执行以下操作:
ALTER DATABASE myDB SET MULTI_USER;
你可能想尝试使用exec而不是sp_exec(不是它应该有任何区别)
SET @killstatement = 'KILL ' + cast(@spid as varchar(3))
EXEC (@killstatement)
您是否尝试过程序运行时实际发生的调试/输出?例如,您可以修改@killstatement以声明为nvarchar(max)并包含一些详细输出(如下所示)并发布结果吗?基本上用以下内容替换开始/结束块中的所有内容:
-- Construct dynamic sql to kill spid
select @killstatement = N'
select *
from sys.dm_exec_sessions s
join sys.dm_exec_connections c
on s.session_id = c.session_id
where c.session_id = @spid;
kill ' + cast(@spid as varchar(3)) + ';
select *
from sys.dm_exec_sessions s
join sys.dm_exec_connections c
on s.session_id = c.session_id
where c.session_id = @spid;
';
-- Print & Exec
print @killstatement;
exec sp_executesql @killstatement, N'@spid smallint', @spid;
print @spid;
没有理由在过程代码中应该有任何不同的行为,而不是在连接中明确执行 - 假设你有适当的权限,杀死有效的spid等等。如果你可以发布一些调试的结果,如以上(以及你可能尝试过的任何其他事情),它将有助于找出问题所在。您可能还希望包含游标声明结果的调试输出,以确保您实际上正在获取要杀死的会话 - 即只需包含您在游标中使用的相同选择以声明输出结果集,如下所示:
declare c1 cursor for select request_session_id
from sys.dm_tran_locks
where resource_type='DATABASE'
AND DB_NAME(resource_database_id) = @database
-- Debug output - sessions we should try and kill...
select request_session_id
from sys.dm_tran_locks
where resource_type='DATABASE'
AND DB_NAME(resource_database_id) = @database;
如果您可以发布结果,希望这会给我们一些事情。
很有可能这些都不适用于您,但以防万一,这里有一些我几年前在处理此类内容时遇到的奇怪情况(所有 SQL 2005)。
- 你不能终止你自己的联系。
- 在我使用的代码中,我确保 绝不 尝试杀死任何低于 51 的 spid。(这些是系统连接;我不知道他们是否能被杀死,但我不会尝试。)
- 如果连接正在处理事务,则必须先回滚该事务,然后才能终止该事务。大量事务可能需要大量时间才能回滚。
- 当心连接池。他们就像不死生物一样——杀死他们,他们就会立即回来,通常在一秒钟之内。
在运行此过程时运行 SQL 事件探查器并跟踪登录和注销可能会有所启发,特别是对于连接池问题。
这适用于SQLServer 2000
DECLARE @DbName VARCHAR(100)
DECLARE @SPID INT
DECLARE @TranUOW UNIQUEIDENTIFIER
DECLARE @KillStmt NVARCHAR(100)
SET @DbName = 'MyDatabase'
-----------------------------------
-- Kill distributed transactions
DECLARE dist CURSOR FOR
SELECT DISTINCT req_transactionUOW
FROM master..syslockinfo
WHERE db_name(rsc_dbid) = @DbName
AND req_transactionUOW <> '00000000-0000-0000-0000-000000000000'
OPEN dist
FETCH NEXT FROM dist INTO @TranUOW
WHILE @@FETCH_STATUS = 0
BEGIN
SET @KillStmt = 'kill ''' + CAST(@TranUOW AS VARCHAR(50)) + ''''
PRINT @KillStmt
EXECUTE(@KillStmt)
FETCH NEXT FROM dist INTO @TranUOW
END
CLOSE dist
DEALLOCATE dist
-----------------------------------
-- Kill user connections
DECLARE cur CURSOR FOR
SELECT spid
FROM master..sysprocesses
WHERE db_name(dbid) = @DbName
AND spid > 50
OPEN cur
FETCH NEXT FROM cur INTO @SPID
WHILE @@FETCH_STATUS = 0
BEGIN
SET @KillStmt = 'kill ' + CAST(@SPID AS VARCHAR(10))
PRINT @KillStmt
EXECUTE(@KillStmt)
FETCH NEXT FROM cur INTO @SPID
END
CLOSE cur
DEALLOCATE cur