SQL Сервер:Завершите процесс с помощью Хранимой процедуры

StackOverflow https://stackoverflow.com/questions/1808366

  •  05-07-2019
  •  | 
  •  

Вопрос

Я хочу изменить следующее, поскольку это, похоже, не убивает процессы - я думаю, что это должно отключать пользователей (это то же самое?).Я хочу иметь возможность завершить все процессы для определенной базы данных - как я могу изменить приведенное ниже:

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

Обновить

Вышесказанное не работает, т.е.это не останавливает процесс.

Это не останавливает процесс.Я смотрю на монитор активности, и он все еще показывает, что процесс продолжается, и я могу видеть, что мой запрос все еще работает в окне запроса.Когда я выполняю "kill 53", выполнение запросов прекращается в окне запроса, и процесс исчезает из activity monitor!Итак, это убийство работает, но не эта процедура, почему?

Это было полезно?

Решение

Я знаком с этим сценарием. Это убивает все SPID, которые используют базу данных, да. Вы должны запустить его с правильными разрешениями - не любой пользователь может убить SPID.

Кроме того, есть вероятность, что у вас могут быть приложения, которые пытаются поддерживать постоянные соединения с БД, и поэтому могут переподключиться вскоре после того, как вы уничтожите их SPID.

Другие советы

Вы просто пытаетесь остановить все действия с определенной БД, чтобы можно было выполнить некоторые операции с ней?

Если это так, вы можете сделать следующее:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

Это уничтожит все остальные SPID, обращающиеся к БД, и переведет БД в однопользовательский режим. Затем выполните действия по обслуживанию и выполните следующие действия:

ALTER DATABASE myDB SET MULTI_USER;

Возможно, вы захотите попробовать использовать exec вместо sp_exec (не то, чтобы это имело какое-либо значение)

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

Вы пробовали какую-либо отладку / вывод того, что на самом деле происходит при запуске процедуры? Например, можете ли вы изменить свой @killstatement так, чтобы он был объявлен как nvarchar (max), и включили несколько подробных выводов, таких как приведенные ниже, и опубликовали результаты? В основном замените все в вашем блоке начала / конца чем-то вроде:

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

Нет никаких причин, по которым что-то должно вести себя по-разному в коде процедуры по сравнению с явным выполнением в соединении - при условии, что у вас есть соответствующие разрешения, вы убиваете допустимые спиды и т. д., и т. д. Если вы можете опубликовать результаты некоторой отладки, например выше (и все, что вы, возможно, пытались), это поможет выяснить, где проблема. Возможно, вы также захотите включить отладочный вывод результатов объявления курсора, который вы используете, чтобы убедиться, что вы фактически получаете сеансы, которые вы пытаетесь уничтожить - т.е. просто включите тот же выбор, который вы используете в объявлении курсора, чтобы вывести набор результатов, например:

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;

Если вы можете опубликовать результаты, надеюсь, это даст нам возможность продолжить.

Велика вероятность, что к вам ничего из этого не относится, но на всякий случай вот несколько странных ситуаций, с которыми я столкнулся, работая над подобными материалами несколько лет назад (весь SQL 2005).

  • Вы не можете уничтожить свою собственную связь.
  • В коде, который я использовал, я позаботился о том, чтобы никогда попытайтесь убить любого spid младше 51 года.(Это системные соединения;Я не знаю, можно ли их убить, но я бы не стал этого делать.)
  • Если соединение обрабатывает транзакцию, оно должно откатить эту транзакцию назад, прежде чем ее можно будет прервать.Откат крупных транзакций может занять значительное время.
  • Остерегайтесь объединения в пул соединений.Они как нежить - убейте их, и они просто вернутся, часто меньше чем за секунду.

Запуск SQL Profiler и отслеживание входов в систему и выходов из системы во время выполнения этого процесса могут оказаться показательными, особенно при проблемах с пулом соединений.

Это работает для меня в 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top