Pergunta

Quero modificar o seguinte, pois ele não parece matar processos - acho que é necessário desconectar os usuários (isso é o mesmo?). Quero poder matar todo o processo para um banco de dados específico - como posso modificar o abaixo:

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

Atualizar

O acima não funciona, ou seja, não mata o processo.

Não mata o processo. Eu olho para o monitor de atividades e ainda mostra o processo continuando e posso ver minha consulta ainda trabalhando na janela de consulta. Quando eu faço "Kill 53", as paradas de consulta na janela da consulta e o processo desapareceu do monitor de atividades! Então, a matança funciona, mas não esse procedimento, por quê?

Foi útil?

Solução

Estou familiarizado com este script. Ele mata todos os spids que estão usando um banco de dados, sim. Você precisa executá -lo sob as permissões corretas - não apenas qualquer usuário pode matar SPIDs.

Além disso, há uma chance de você ter aplicativos que tentam manter conexões persistentes com o banco de dados e, portanto, podem se reconectar logo após matar o SPID deles.

Outras dicas

Você está apenas tentando interromper toda a atividade em um banco de dados específico para poder fazer alguma manutenção nele?

Nesse caso, você pode fazer o seguinte:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

Isso matará todos os outros espides acessando o banco de dados e colocará o banco de dados no modo de usuário único. Em seguida, execute sua ação de manutenção e faça o seguinte depois:

ALTER DATABASE myDB SET MULTI_USER;

Você pode tentar usar o EXEC em vez do sp_exec (não que ele faça alguma diferença)

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

Você já tentou alguma depuração/saída do que realmente ocorre quando o procedimento é executado? Por exemplo, você pode modificar você @killstatement a ser declarado como nvarchar (max) e incluir alguma saída detalhada, como a seguinte e postar os resultados? Basicamente, substitua tudo no seu bloco de início/final por algo como:

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

Não há razão para que algo deva se comportar de maneira diferente dentro do código do procedimento versus executar explicitamente dentro de uma conexão - supondo que você tenha as permissões apropriadas, está matando espides válidos, etc. etc. se você puder postar os resultados de alguma depuração como o acima ( E qualquer outra coisa que você possa ter tentado), ajudaria a descobrir onde está o problema. Você também pode querer incluir uma saída de depuração dos resultados do cursor que está usando para garantir que você esteja realmente obtendo as sessões que está tentando matar - ou seja, inclua a mesma seleção que você está usando no seu cursor declarar para produzir uma saída A Conjunto de resultados, assim:

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;

Se você puder postar os resultados, espero que isso nos dê algo para continuar.

As chances são boas de que nenhuma delas se aplique a você, mas, para o caso de aqui algumas situações estranhas que encontrei ao trabalhar em coisas assim alguns anos atrás (todos os SQL 2005).

  • Você não pode matar sua própria conexão.
  • No código que usei, certifiquei -me Nunca Tente matar qualquer SPID abaixo de 51. (Essas são conexões do sistema; não sei se elas podem ser mortas, mas eu não tentaria.)
  • Se uma conexão estiver processando uma transação, ela terá que reverter essa transação antes que ela possa ser morta. Transações enormes podem levar um tempo significativo para reverter.
  • Cuidado com o pool de conexão. Eles são como os mortos-vivos-matam-os, e eles voltam diretamente, em menos de um segundo.

Executar o SQL Profiler e rastrear logins e logouts enquanto você executa esse processo pode ser revelador, principalmente para problemas de agrupamento de conexões.

Isso funciona para mim no 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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top