Domanda

Voglio modificare quanto segue poiché non sembra uccidere i processi - penso che dovrebbe disconnettere gli utenti (è lo stesso?). Voglio essere in grado di terminare tutto il processo per un determinato database - come posso modificare quanto segue:

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

Aggiornamento

Quanto sopra non funziona, cioè non uccide il processo.

  

Non uccide il processo. guardo a   il monitor attività e il suo fermo   mostra che il processo continua e io posso   vedere la mia query ancora funzionante in   finestra di query. Quando faccio "uccidere 53", il   l'interrogazione si interrompe nella finestra dell'interrogazione e   il processo è passato dall'attività   tenere sotto controllo! Quindi l'uccisione funziona ma non questa procedura perché?

È stato utile?

Soluzione

Conosco bene questo script. Uccide tutti gli SPID che utilizzano un database, sì. Devi eseguirlo con le autorizzazioni corrette, non tutti gli utenti possono uccidere gli SPID.

Inoltre, è possibile che siano presenti applicazioni che tentano di mantenere connessioni persistenti al DB e pertanto potrebbero riconnettersi poco dopo aver ucciso il loro SPID.

Altri suggerimenti

Stai solo cercando di interrompere tutte le attività su un determinato DB in modo da poter fare un po 'di manutenzione su di esso?

In tal caso, puoi eseguire le seguenti operazioni:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

Questo ucciderà tutti gli altri SPID che accedono al DB e metterà il DB in modalità utente singolo. Quindi eseguire le operazioni di manutenzione e procedere come segue:

ALTER DATABASE myDB SET MULTI_USER;

Potresti provare a usare exec invece di sp_exec (non che dovrebbe fare alcuna differenza)

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

Hai provato a eseguire il debug / output di ciò che si verifica effettivamente quando viene eseguita la procedura? Ad esempio, puoi modificare @killstatement per essere dichiarato come nvarchar (max) e includere un output dettagliato come il seguente e pubblicare i risultati? Sostanzialmente sostituisci tutto nel tuo blocco iniziale / finale con qualcosa del tipo:

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

Non vi è alcun motivo per cui qualcosa dovrebbe comportarsi in modo diverso all'interno del codice della procedura rispetto all'esecuzione esplicita all'interno di una connessione - supponendo che tu abbia le autorizzazioni appropriate, stia uccidendo spid validi, ecc. ecc. Se puoi pubblicare i risultati di alcuni debug come quanto sopra (e qualsiasi altra cosa tu possa aver provato), aiuterebbe a capire dov'è il problema. Potresti anche voler includere un output di debug dei risultati del cursore dichiarare che stai utilizzando per assicurarti di ottenere effettivamente le sessioni che stai tentando di uccidere - vale a dire semplicemente includere la stessa selezione che stai usando nel cursore dichiarare di produrre un set di risultati, in questo modo:

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 puoi pubblicare i risultati, speriamo che ci dia qualcosa da fare.

Le probabilità sono buone che nessuna di queste si applichi a te, ma nel caso in cui qui ci siano alcune situazioni strane che ho incontrato lavorando su cose come questa qualche anno fa (tutto SQL 2005).

  • Non puoi uccidere la tua connessione.
  • Nel codice che ho usato, mi sono assicurato di non mai tentare di uccidere qualsiasi spid sotto 51. (Queste sono connessioni di sistema; non so se possono essere uccise, ma non vorrei provalo.)
  • Se una connessione sta elaborando una transazione, deve eseguire il rollback di quella transazione prima che possa essere interrotta. Transazioni enormi possono richiedere molto tempo per il rollback.
  • Attenzione al pool di connessioni. Sono come i non morti: uccidili e tornano subito, spesso in meno di un secondo.

L'esecuzione di SQL Profiler e il monitoraggio di accessi e disconnessioni durante l'esecuzione di questo processo potrebbero rivelare problemi, in particolare per problemi di pool di connessioni.

Questo funziona per 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top