views:

1507

answers:

6

Hello all,

I want to modify the following as it doesn't seem to kill processes - I think its supposed to disconnect users (is this the same?). I want to be able to kill all process for a particular database - how can I modify the below:

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

Update

The above doesn't work i.e. it doesn't kill the process.

It doesn't kill the process. I look at the activity monitor and its still shows the process continuing and I can see my query still working in the query window. When I do "kill 53", the querying stops in the query window and the process is gone from the activity monitor! So th kill works but not this procedure why?

+1  A: 

I'm familiar with this script. It kills all SPIDs that are using a database, yes. You need to run it under the correct permissions - not just any user can kill SPIDs.

Also, there's a chance you may have applications that try and maintain persistent connections to the DB, and therefore may reconnect shortly after you kill their SPID.

Randolph Potter
I am logged in with my account - I run my own query and then I use "Kill 53" and it kills the process for me. I wanted to do the same with this stored procedure. I will always be killing process that I have run so I should have the right permissions to do this?
Abs
I see. Which version of SQL are you running? This script only runs on 2005+.
Randolph Potter
Yes, I am using SQL 2005 there was a 2000 one but I opted for this one ofcourse! :) Has this script worked for you? Is there anything else that I need to make sure of?
Abs
What error messages are you getting? How do you know it isn't working?
Randolph Potter
It doesn't kill the process. I look at the activity monitor and its still shows the process continuing and I can see my query still working in the query window. When I do "kill 53", the querying stops in the query window and the process is gone from the activity monitor!
Abs
Open SQL Profiler. Create a trace on your server. Capture the events for the above script. Put the error message here and we'll tell you what is or isn't happening. Without any of that information, we cannot help you.
Randolph Potter
I've somehow managed to get it working! :)
Abs
Good to know! :-)
Randolph Potter
A: 

You might want to try using exec instead of sp_exec (not that it should make any difference)

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

Have you tried any debugging/output of what actually occurs when the procedure is run? For example, can you modify you @killstatement to be declared as nvarchar(max) and include some verbose output such as the following and post the results? Basically replace everything within your begin/end block with something like:

-- 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;

There's no reason anything should be behaving differently within the procedure code vs. executing explicitly within a connection - assuming you have the appropriate permissions, are killing valid spids, etc., etc. If you can post the results of some debugging like the above (and anything else you may have tried), it would help figure out where the issue is. You might also want to include a debug output of the results of the cursor declare you are using to make sure you are actually getting the sessions you are trying to kill - i.e. simply include the same select you are using in your cursor declare to output a result set, like this:

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;

If you can post the results, hopefully that will give us something to go on.

chadhoc
A: 

Odds are good that none of these apply to you, but just in case here are some oddball situations I encountered when working on stuff like this a few years back (all SQL 2005).

  • You can't kill your own connection.
  • In the code I used, I made sure to never try and kill any spid under 51. (These are system connections; I don't know if they can be killed, but I wouldn't try it.)
  • If a connection is processing a transaction, it has to roll that transaction back before it can be killed. Huge transactions can take significant time to roll back.
  • Beware connection pooling. They're like the undead--kill them, and they just come right back, often in under a second.

Running SQL Profiler and tracking logins and logouts while you run this process might be revealing, particularly for connection pooling issues.

Philip Kelley
+2  A: 

Are you just trying to stop all activity on a particular DB so you can do some maintenance on it?

If so, you can do the following:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

This will kill all other SPIDs accessing the DB, and will put the DB in single-user mode. Then perform your maintenance action, and do the following afterwards:

ALTER DATABASE myDB SET MULTI_USER;
Richard Beier
A: 

This works for me in 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
alygin