Pregunta

Quiero modificar lo siguiente, ya que parece que no mata los procesos. Creo que se supone que desconecta a los usuarios (¿es esto lo mismo?). Quiero poder eliminar todos los procesos de una base de datos en particular. ¿Cómo puedo modificar lo siguiente?

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

Actualizar

Lo anterior no funciona, es decir, no detiene el proceso.

  

No mata el proceso. miro a   el monitor de actividad y su todavía   muestra el proceso continuando y puedo   ver mi consulta sigue trabajando en el   ventana de consulta Cuando hago " mata 53 " ;, el   consulta se detiene en la ventana de consulta y   El proceso se ha ido de la actividad.   ¡monitor! Así que la matanza funciona, pero no este procedimiento, ¿por qué?

¿Fue útil?

Solución

Estoy familiarizado con este script. Elimina todos los SPID que usan una base de datos, sí. Debe ejecutarlo con los permisos correctos, no cualquier usuario puede anular los SPID.

También, existe la posibilidad de que tengas aplicaciones que intenten y mantengan conexiones persistentes con la base de datos, y por lo tanto, puedan volver a conectarse poco después de que hayas eliminado su SPID.

Otros consejos

¿Estás tratando de detener toda la actividad en una base de datos en particular para poder hacer un mantenimiento?

Si es así, puedes hacer lo siguiente:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

Esto eliminará todos los demás SPID que accedan a la base de datos y pondrá la base de datos en modo de usuario único. Luego realice su acción de mantenimiento, y haga lo siguiente después:

ALTER DATABASE myDB SET MULTI_USER;

Es posible que desee intentar usar exec en lugar de sp_exec (no es que deba hacer ninguna diferencia)

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

¿Ha intentado alguna depuración / salida de lo que realmente ocurre cuando se ejecuta el procedimiento? Por ejemplo, ¿puede modificar su @killstatement para que se declare como nvarchar (max) e incluir algunos resultados detallados como los siguientes y publicar los resultados? Básicamente, reemplaza todo dentro de tu bloque de inicio / final con 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;

No hay ninguna razón para que algo se comporte de manera diferente dentro del código de procedimiento en lugar de ejecutarse explícitamente dentro de una conexión, asumiendo que tiene los permisos adecuados, está matando a spids válidos, etc., etc. Si puede publicar los resultados de una depuración como Lo anterior (y cualquier otra cosa que haya intentado), ayudaría a descubrir dónde está el problema. También es posible que desee incluir una salida de depuración de los resultados de la declaración del cursor que está utilizando para asegurarse de que realmente está obteniendo las sesiones que está intentando eliminar, es decir, simplemente incluya la misma selección que está utilizando en su declaración de cursor para generar una conjunto de resultados, como este:

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;

Si puede publicar los resultados, espero que eso nos brinde algo para continuar.

Hay muchas probabilidades de que ninguno de estos se aplique a ti, pero por si acaso hay algunas situaciones extrañas que encontré cuando trabajé en cosas como esta hace algunos años (todo SQL 2005).

  • No puedes matar tu propia conexión.
  • En el código que utilicé, me aseguré de nunca intentar matar a cualquier spid menor de 51. (Estas son las conexiones del sistema; no sé si pueden matarse, pero no lo haría ». t intentarlo.)
  • Si una conexión está procesando una transacción, debe deshacer esa transacción antes de que se pueda cancelar. Las grandes transacciones pueden demorar un tiempo considerable en revertirse.
  • Cuidado con la agrupación de conexiones. Son como los muertos vivientes: mátalos y regresan, a menudo en menos de un segundo.

La ejecución del Analizador de SQL y el seguimiento de inicios de sesión y cierres de sesión mientras ejecuta este proceso puede ser reveladora, en particular para los problemas de agrupación de conexiones.

Esto funciona para mí en 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top