【问题标题】:SQL Server: Kill Process using Stored ProcedureSQL Server:使用存储过程终止进程
【发布时间】:2009-11-27 12:05:14
【问题描述】:

我想修改以下内容,因为它似乎不会杀死进程 - 我认为它应该断开用户连接(这是一样的吗?)。我希望能够杀死特定数据库的所有进程 - 如何修改以下内容:

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”时, 查询在查询窗口中停止,并且 该过程已从活动中消失 监视器!所以杀死工作,但这个过程为什么不?

【问题讨论】:

  • 你能定义你所说的“杀死进程”是什么意思吗?我认为不可能从存储过程中终止常规 Windows 进程(无论如何这会很奇怪,请考虑为此编写应用程序)。
  • 我说的是 SQL Server - 以及 SQL Server 中的进程。试图杀死 SQL Server 而不是 windows 中的进程/查询。

标签: sql-server process kill


【解决方案1】:

您是否只是试图停止特定数据库上的所有活动,以便对其进行一些维护?

如果是这样,您可以执行以下操作:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

这将杀死所有其他访问数据库的 SPID,并将数据库置于单用户模式。然后执行您的维护操作,然后执行以下操作:

ALTER DATABASE myDB SET MULTI_USER;

【讨论】:

    【解决方案2】:

    我对这个脚本很熟悉。它会杀死所有使用数据库的 SPID,是的。您需要在正确的权限下运行它 - 不仅仅是任何用户都可以杀死 SPID。

    此外,您的应用程序可能会尝试保持与数据库的持久连接,因此可能会在您终止其 SPID 后不久重新连接。

    【讨论】:

    • 打开 SQL Profiler。在您的服务器上创建跟踪。捕获上述脚本的事件。将错误消息放在这里,我们会告诉您发生了什么或没有发生什么。如果没有任何这些信息,我们将无法为您提供帮助。
    【解决方案3】:

    您可能想尝试使用 exec 而不是 sp_exec(不是说它应该有任何区别)

    SET @killstatement = 'KILL ' + cast(@spid as varchar(3)) 
    EXEC (@killstatement)
    

    【讨论】:

      【解决方案4】:

      您是否尝试过任何调试/输出程序运行时实际发生的情况?例如,您是否可以将 @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;
      

      如果你能发布结果,希望这会给我们一些东西。

      【讨论】:

        【解决方案5】:

        这些都不适用于您的可能性很大,但以防万一几年前我在从事此类工作时遇到了一些奇怪的情况(所有 SQL 2005)。

        • 您不能终止自己的连接。
        • 在我使用的代码中,我确保从不尝试杀死任何低于 51 的 spid。(这些是系统连接;我不知道它们是否可以被杀死,但我不会'不要尝试。)
        • 如果一个连接正在处理一个事务,它必须回滚该事务才能被终止。大量事务可能需要很长时间才能回滚。
        • 当心连接池。它们就像不死生物——杀死它们,它们就会马上回来,通常不到一秒钟。

        在运行此过程时运行 SQL Profiler 并跟踪登录和注销可能会发现问题,尤其是对于连接池问题。

        【讨论】:

          【解决方案6】:

          这适用于我在 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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多