SQL Server: عملية القتل باستخدام الإجراء المخزن

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" ، يتوقف الاستعلام في نافذة الاستعلام وذهب العملية من شاشة النشاط! لذا فإن القتل يعمل ولكن ليس هذا الإجراء لماذا؟

هل كانت مفيدة؟

المحلول

أنا على دراية بهذا السيناريو. إنه يقتل جميع السدادات التي تستخدم قاعدة بيانات ، نعم. تحتاج إلى تشغيله تحت الأذونات الصحيحة - وليس فقط أي مستخدم يمكن أن يقتل السدادات.

أيضًا ، هناك فرصة لك قد يكون لديك تطبيقات تحاول الحفاظ على اتصالات مستمرة مع DB ، وبالتالي قد تقوم بإعادة الاتصال بعد فترة وجيزة من قتل Spid.

نصائح أخرى

هل تحاول فقط إيقاف كل النشاط على ديسيبل معين حتى تتمكن من القيام ببعض الصيانة؟

إذا كان الأمر كذلك ، يمكنك القيام بما يلي:

ALTER DATABASE myDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

سيؤدي ذلك إلى قتل جميع السدادات الأخرى التي تصل إلى DB ، وسيضع DB في وضع المستخدم الواحد. ثم قم بإجراء إجراء الصيانة ، وقم بما يلي بعد ذلك:

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).

  • لا يمكنك قتل اتصالك الخاص.
  • في الكود الذي استخدمته ، تأكدت من ذلك أبداً حاول أن تقتل أي سبد أقل من 51. (هذه هي اتصالات النظام ؛ لا أعرف ما إذا كان يمكن قتلها ، لكنني لن أحاول ذلك.)
  • إذا كان الاتصال يعالج معاملة ، فيجب عليه أن يلف هذه المعاملة قبل أن يتم قتله. يمكن أن تستغرق المعاملات الضخمة وقتًا كبيرًا للتراجع.
  • حذار تجميع الاتصال. إنهم مثل أوندد-خلكهم ، وهم يعودون مباشرة ، وغالبًا ما يكونون في الثانية.

قد يكون تشغيل SQL Profiler وتتبع تسجيلات تسجيل الدخول و Logouts أثناء تشغيل هذه العملية يكشف ، خاصة بالنسبة لمشكلات تجميع الاتصالات.

هذا يعمل بالنسبة لي في 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