Script to kill all connections to a database (More than RESTRICTED_USER ROLLBACK)

后端 未结 14 1502
-上瘾入骨i
-上瘾入骨i 2020-11-28 17:28

I have a development database that re-deploy frequently from a Visual Studio Database project (via a TFS Auto Build).

Sometimes when I run my build I get this error:

相关标签:
14条回答
  • 2020-11-28 17:37
    SELECT
        spid,
        sp.[status],
        loginame [Login],
        hostname, 
        blocked BlkBy,
        sd.name DBName, 
        cmd Command,
        cpu CPUTime,
        memusage Memory,
        physical_io DiskIO,
        lastwaittype LastWaitType,
        [program_name] ProgramName,
        last_batch LastBatch,
        login_time LoginTime,
        'kill ' + CAST(spid as varchar(10)) as 'Kill Command'
    FROM master.dbo.sysprocesses sp 
    JOIN master.dbo.sysdatabases sd ON sp.dbid = sd.dbid
    WHERE sd.name NOT IN ('master', 'model', 'msdb') 
    --AND sd.name = 'db_name' 
    --AND hostname like 'hostname1%' 
    --AND loginame like 'username1%'
    ORDER BY spid
    
    /* If a service connects continously. You can automatically execute kill process then run your script:
    DECLARE @sqlcommand nvarchar (500)
    SELECT @sqlcommand = 'kill ' + CAST(spid as varchar(10))
    FROM master.dbo.sysprocesses sp 
    JOIN master.dbo.sysdatabases sd ON sp.dbid = sd.dbid
    WHERE sd.name NOT IN ('master', 'model', 'msdb') 
    --AND sd.name = 'db_name' 
    --AND hostname like 'hostname1%' 
    --AND loginame like 'username1%'
    --SELECT @sqlcommand
    EXEC sp_executesql @sqlcommand
    */
    
    0 讨论(0)
  • 2020-11-28 17:41
    USE master
    GO
    ALTER DATABASE database_name
    SET OFFLINE WITH ROLLBACK IMMEDIATE
    GO
    

    Ref: http://msdn.microsoft.com/en-us/library/bb522682%28v=sql.105%29.aspx

    0 讨论(0)
  • 2020-11-28 17:42

    You can use Cursor like that:

    USE master
    GO
    
    DECLARE @SQL AS VARCHAR(255)
    DECLARE @SPID AS SMALLINT
    DECLARE @Database AS VARCHAR(500)
    SET @Database = 'AdventureWorks2016CTP3'
    
    DECLARE Murderer CURSOR FOR
    SELECT spid FROM sys.sysprocesses WHERE DB_NAME(dbid) = @Database
    
    OPEN Murderer
    
    FETCH NEXT FROM Murderer INTO @SPID
    WHILE @@FETCH_STATUS = 0
    
        BEGIN
        SET @SQL = 'Kill ' + CAST(@SPID AS VARCHAR(10)) + ';'
        EXEC (@SQL)
        PRINT  ' Process ' + CAST(@SPID AS VARCHAR(10)) +' has been killed'
        FETCH NEXT FROM Murderer INTO @SPID
        END 
    
    CLOSE Murderer
    DEALLOCATE Murderer
    

    I wrote about that in my blog here: http://www.pigeonsql.com/single-post/2016/12/13/Kill-all-connections-on-DB-by-Cursor

    0 讨论(0)
  • 2020-11-28 17:44

    @AlexK wrote a great answer. I just want to add my two cents. The code below is entirely based on @AlexK's answer, the difference is that you can specify the user and a time since the last batch was executed (note that the code uses sys.dm_exec_sessions instead of master..sysprocess):

    DECLARE @kill varchar(8000);
    set @kill =''
    select @kill = @kill + 'kill ' +  CONVERT(varchar(5), session_id) + ';' from sys.dm_exec_sessions 
    where login_name = 'usrDBTest'
    and datediff(hh,login_time,getdate()) > 1
    --and session_id in (311,266)    
    exec(@kill)
    

    In this example only the process of the user usrDBTest which the last batch was executed more than 1 hour ago will be killed.

    0 讨论(0)
  • 2020-11-28 17:44

    This solution worked for me.

    DECLARE @kill varchar(8000) = '';  
    SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), session_id) + ';'  
    FROM sys.dm_exec_sessions
    WHERE database_id  = db_id('MyDB')
    
    EXEC(@kill);
    
    0 讨论(0)
  • 2020-11-28 17:46

    The accepted answer has the drawback that it doesn't take into consideration that a database can be locked by a connection that is executing a query that involves tables in a database other than the one connected to.

    This can be the case if the server instance has more than one database and the query directly or indirectly (for example through synonyms) use tables in more than one database etc.

    I therefore find that it sometimes is better to use syslockinfo to find the connections to kill.

    My suggestion would therefore be to use the below variation of the accepted answer from AlexK:

    USE [master];
    
    DECLARE @kill varchar(8000) = '';  
    SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), req_spid) + ';'  
    FROM master.dbo.syslockinfo
    WHERE rsc_type = 2
    AND rsc_dbid  = db_id('MyDB')
    
    EXEC(@kill);
    
    0 讨论(0)
提交回复
热议问题