SQL Server: Kill Process à l'aide d'une procédure stockée
-
05-07-2019 - |
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?
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