Question

Je souhaite modifier ce qui suit, car il ne semble pas tuer les processus. Je pense que cela est supposé déconnecter les utilisateurs (est-ce la même chose?). Je veux pouvoir tuer tous les processus d'une base de données particulière. Comment puis-je modifier les éléments ci-dessous:

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

Mettre à jour

Ce qui précède ne fonctionne pas, c'est-à-dire qu'il ne tue pas le processus.

  

Cela ne tue pas le processus. je regarde a   le moniteur d'activité et son alambic   montre le processus en cours et je peux   voir ma requête fonctionne toujours dans le   fenêtre de requête. Quand je fais "tuer 53", le   l'interrogation s'arrête dans la fenêtre de requête et   le processus est parti de l'activité   moniteur! Donc, tuer fonctionne mais pas cette procédure, pourquoi?

Était-ce utile?

La solution

Je connais ce script. Oui, il tue tous les SPID utilisant une base de données. Vous devez l'exécuter sous les autorisations appropriées. Tous les utilisateurs ne peuvent tuer les SPID.

En outre, il est possible que certaines applications tentent de conserver des connexions persistantes à la base de données et, par conséquent, se reconnectent peu de temps après la suppression de leur SPID.

Autres conseils

Essayez-vous simplement d'arrêter toute activité sur une base de données particulière pour pouvoir effectuer des tâches de maintenance?

Si tel est le cas, vous pouvez procéder comme suit:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

Cela supprimera tous les autres SPID accédant à la base de données et mettra la base de données en mode mono-utilisateur. Exécutez ensuite votre action de maintenance, puis procédez comme suit:

ALTER DATABASE myDB SET MULTI_USER;

Vous voudrez peut-être essayer d'utiliser exec au lieu de sp_exec (cela ne changera rien).

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

Avez-vous essayé un débogage / une sortie de ce qui se passe réellement lorsque la procédure est exécutée? Par exemple, pouvez-vous modifier votre @killstatement pour être déclaré en tant que nvarchar (max) et inclure des sorties verbeuses telles que ce qui suit et publier les résultats? En gros, remplacez tout ce qui se trouve dans votre bloc begin / end par quelque chose comme:

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

Il n'y a aucune raison que le code de procédure opère différemment par rapport à une exécution explicite au sein d'une connexion - en supposant que vous disposez des autorisations appropriées, que vous supprimiez des spids valides, etc., etc. Si vous pouvez publier les résultats d'un débogage tel que ci-dessus (et tout ce que vous avez pu essayer), il serait utile de déterminer où se situe le problème. Vous pouvez également vouloir inclure une sortie de débogage des résultats du curseur déclare que vous utilisez pour vous assurer que vous obtenez bien les sessions que vous essayez de tuer - c’est-à-dire que vous incluez simplement la même sélection que celle que vous utilisez dans votre curseur jeu de résultats, comme ceci:

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 vous pouvez afficher les résultats, j'espère que cela nous donnera de quoi continuer.

Les chances sont bonnes qu'aucune de celles-ci ne vous concerne, mais juste au cas où il y a des situations étranges que j'ai rencontrées lorsque j'ai travaillé sur de telles choses il y a quelques années (tout SQL 2005).

  • Vous ne pouvez pas tuer votre propre connexion.
  • Dans le code que j'ai utilisé, je me suis assuré de ne jamais essayer de tuer les spid de moins de 51 ans (ce sont des connexions système; je ne sais pas si elles peuvent être tuées, mais je ne le ferais pas. pas essayer.)
  • Si une connexion est en train de traiter une transaction, elle doit la restaurer avant de pouvoir la tuer. Des transactions énormes peuvent prendre beaucoup de temps pour revenir en arrière.
  • Faites attention au regroupement de connexions. Ils sont comme les morts-vivants - tuez-les, et ils reviennent tout de suite, souvent en moins d’une seconde.

L'exécution de SQL Profiler et le suivi des connexions et des déconnexions pendant l'exécution de ce processus peuvent être révélateurs, en particulier pour les problèmes de regroupement de connexions.

Cela fonctionne pour moi dans 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top