데이터베이스에 대한 모든 연결을 종료하는 스크립트 (RESTTEDTED_USER ROLLBACK 이상)


239

Visual Studio 데이터베이스 프로젝트에서 자주 배포하는 개발 데이터베이스가 있습니다 (TFS 자동 빌드를 통해).

때로는 빌드를 실행할 때 다음 오류가 발생합니다.

ALTER DATABASE failed because a lock could not be placed on database 'MyDB'. Try again later.  
ALTER DATABASE statement failed.  
Cannot drop database "MyDB" because it is currently in use.  

나는 이것을 시도했다 :

ALTER DATABASE MyDB SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE

하지만 여전히 데이터베이스를 삭제할 수 없습니다. (제 생각에는 대부분의 개발자가 dbo액세스 할 수 있습니다.)

SP_WHO연결을 수동으로 실행 하고 종료 할 수 있지만 자동 빌드에서이를 수행하는 자동 방법이 필요합니다. (이번에도 내 연결은 삭제하려는 DB의 유일한 연결입니다.)

누가 연결되어 있는지에 관계없이 데이터베이스를 삭제할 수있는 스크립트가 있습니까?

답변:


642

업데이트

MS SQL Server 2012 이상

USE [master];

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

MS SQL Server 2000, 2005, 2008

USE master;

DECLARE @kill varchar(8000); SET @kill = '';  
SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), spid) + ';'  
FROM master..sysprocesses  
WHERE dbid = db_id('MyDB')

EXEC(@kill); 

25
이것이 두 사람의 더 나은 대답입니다. 데이터베이스를 오프라인 상태로 만들지 않고 허용되는 답변이 항상 작동하지는 않습니다 (때로는 모든 것을 롤백 할 수 없음).
마크 헨더슨

3
kill성명을 모두 종합 한 훌륭한 답변입니다 . 커서를 사용하여 각 프로세스를 죽일 것입니다. 물론 전혀 효율적이지 않습니다. 이 답변에 사용 된 기술은 훌륭합니다.
Saeed Neamati

마크에 동의합니다. 이 방법은 데이터베이스에 훨씬 더 우아하고 영향을 덜 미치기 때문에 수용된 대답이어야합니다.
Austin S.

3
좋은 하나와 빠른. 문제는 시스템 spid 일 수 있으므로 u를 어디에 추가 할 수 있습니다. dbid = db_id ( 'My_db') 및 spid> 50
Saurabh Sinha

1
@FrenkyB 스크립트를 실행하기 전에 데이터베이스 컨텍스트를 변경해야합니다. 예 :USE [Master]
AlexK

133
USE master
GO
ALTER DATABASE database_name
SET OFFLINE WITH ROLLBACK IMMEDIATE
GO

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


9
이상하게도 그것이 USE master핵심이었습니다. 연결되어있는 동안 DB를 삭제하려고했습니다 (Duh!). 감사!
Vaccano

9
사용하는 경우 SET OFFLINEdb 파일을 수동으로 삭제해야합니다.
mattalxndr

5
alter database YourDatabaseName set SINGLE_USER with rollback immediate더 좋지 않을까요 ? OFFLINE@mattalxndr 상태로 설정 하면 파일은 디스크에 남아 있지만 SINGLE_USER연결 상태는 유일하게 남아 있으며 drop database YourDatabaseName여전히 파일을 제거합니다.
Keith

1
스크립트에서 @Keith, 당신은 DB에 연결되어 있지 않으므로 "연결"이 아니라 남겨질 다른 것입니다. 의 바로 뒤에 남은 파일 문제를 피하기 위해 set offline발행 할 수 있습니다 set online(경쟁 조건이있을 수 있습니다).
ivan_pozdeev

2
감사! 이 데이터베이스에서 이전에 실행 된 SQL Management Studio의 sql 문이있는 일부 탭으로 인해 DB 사용이보고되었다는 사실을 알지 못했습니다. 마스터를 사용하고 모든 것이 제대로 작동하도록하십시오!
eythort

26

다음을 수행하여 SSMS가 제공하는 스크립트를 얻을 수 있습니다.

  1. SSMS에서 데이터베이스를 마우스 오른쪽 버튼으로 클릭하고 삭제를 선택하십시오.
  2. 대화 상자에서 "기존 연결 닫기"확인란을 선택하십시오.
  3. 대화 상자 상단의 스크립트 버튼을 클릭하십시오.

스크립트는 다음과 같습니다.

USE [master]
GO
ALTER DATABASE [YourDatabaseName] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
DROP DATABASE [YourDatabaseName]
GO

3
DBB에 연결되어있는 경우 SQL Server를 다시 시작 해야하는 경우 일부 응용 프로그램 사용자와의 현재 연결이 느슨해져 해당 사용자를 찾는 데 불필요 한 문제가 발생할 수 있으므로 단일 사용자 모드에서 databse를 사용하지 않는 것이 좋습니다. 너무 자주.
Saurabh Sinha 님의

7

거의 알려지지 않음 : GO sql 문은 이전 명령을 반복하는 데 여러 번 정수를 사용할 수 있습니다.

따라서 당신이 :

ALTER DATABASE [DATABASENAME] SET SINGLE_USER
GO

그때:

USE [DATABASENAME]
GO 2000

USE 명령을 2000 번 반복하고 다른 모든 연결에서 교착 상태를 강제 실행하고 단일 연결의 소유권을 갖습니다. (원하는대로 쿼리 창에 단독 액세스 권한을 부여하십시오.)


2
GO는 TSQL 명령이 아니라 sqlcmd 및 osql 유틸리티와 SSMS에서만 인식되는 특수 명령입니다.
diceless

4

내 경험상 SINGLE_USER를 사용하면 대부분 도움이되지만 조심해야합니다 .SINGLE_USER 명령을 시작한 시간과 완료 된 시간 사이에 다른 '사용자'가 생겼습니다. 내가 아닌 SINGLE_USER 액세스 이런 일이 발생하면 데이터베이스에 다시 액세스하려고하는 힘든 일을하고 있습니다 (제 경우에는 SINGLE_USER 액세스를 보유한 SQL 데이터베이스가있는 소프트웨어에 대해 특정 서비스가 실행 중이었습니다). 가장 신뢰할 수있는 방법이어야한다고 생각합니다 (보증 할 수는 없지만 앞으로 테스트 할 것입니다). 실제로는 다음과 같습니다
- 액세스를 방해 할 수 있습니다 스톱 서비스 (어떤이있는 경우)
- 위의 'kill'스크립트를 사용하여 모든 연결을 닫으십시오
-그 직후 데이터베이스를 single_user로 설정
한 다음 복원을 수행하십시오.


SINGLE_USER 명령이 (스크립팅 된) restore 명령과 동일한 배치에 있으면 GO 문으로 분리되지 않습니다! 내 경험으로는 다른 프로세스가 단일 사용자 액세스를 가져올 수 없습니다. 그러나 오늘 밤 예약 된 단일 사용자, 복원, 세트 다중 사용자 작업이 폭발하여 오늘 밤에 체포되었습니다. 다른 프로세스는 내 bak 파일 (smh)에 독점적 인 파일 액세스 권한을 가지고 있으므로 복원에 실패했으며 SET MULTI_USER 실패 ... 혈당을 청소하기 위해 심야에 전화를 받았을 때 다른 사람이 SINGLE_USER 액세스 권한을 가졌습니다. 죽여야 했어요
Ross Presser

3

Matthew의 가장 효율적인 스크립트는 dm_exec_sessions DMV를 사용하도록 업데이트되어 더 이상 사용되지 않는 sysprocesses 시스템 테이블을 대체합니다.

USE [master];
GO

DECLARE @Kill VARCHAR(8000) = '';

SELECT
    @Kill = @Kill + 'kill ' + CONVERT(VARCHAR(5), session_id) + ';'
FROM
    sys.dm_exec_sessions
WHERE
    database_id = DB_ID('<YourDB>');

EXEC sys.sp_executesql @Kill;

WHILE 루프를 사용하는 대안 (실행마다 다른 작업을 처리하려는 경우) :

USE [master];
GO

DECLARE @DatabaseID SMALLINT = DB_ID(N'<YourDB>');    
DECLARE @SQL NVARCHAR(10);

WHILE EXISTS ( SELECT
                1
               FROM
                sys.dm_exec_sessions
               WHERE
                database_id = @DatabaseID )    
    BEGIN;
        SET @SQL = (
                    SELECT TOP 1
                        N'kill ' + CAST(session_id AS NVARCHAR(5)) + ';'
                    FROM
                        sys.dm_exec_sessions
                    WHERE
                        database_id = @DatabaseID
                   );
        EXEC sys.sp_executesql @SQL;
    END;

2

허용되는 답변에는 연결된 데이터베이스 이외의 데이터베이스에있는 테이블이 포함 된 쿼리를 실행하는 연결에 의해 데이터베이스를 잠글 수 없다는 단점이 있습니다.

서버 인스턴스에 둘 이상의 데이터베이스가 있고 쿼리가 직접 또는 간접적으로 (예를 들어 동의어를 통해) 둘 이상의 데이터베이스에서 테이블을 사용하는 경우에 해당됩니다.

따라서 때때로 syslockinfo를 사용하여 종료 할 연결을 찾는 것이 더 낫다는 것을 알았습니다.

따라서 내 제안은 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);

이! 더 이상 사용되지 않는 것으로 표시된 sys.dm_tran_locks표를 개인적으로 사용하지만 syslockinfo경우에 따라 현재 @@ SPID를 제외 할 수도 있습니다.
deroby

1

강제 종료 프로세스 중 예외에주의해야합니다. 따라서이 스크립트를 사용할 수 있습니다 :

USE master;
GO
 DECLARE @kill varchar(max) = '';
 SELECT @kill = @kill + 'BEGIN TRY KILL ' + CONVERT(varchar(5), spid) + ';' + ' END TRY BEGIN CATCH END CATCH ;' FROM master..sysprocesses 
EXEC (@kill)

1

@AlexK는 훌륭한 답변을 썼습니다 . 나는 단지 2 센트를 더하고 싶다. 아래 코드는 전적으로 @AlexK의 답변을 기반으로하지만 차이점은 마지막 배치가 실행 된 후 사용자와 시간을 지정할 수 있다는 것입니다 (코드는 master..sysprocess 대신 sys.dm_exec_sessions를 사용합니다).

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)

이 예제에서는 마지막 배치가 1 시간 이상 실행 된 usrDBTest 사용자 프로세스 만 종료됩니다.


1

커서를 다음 과 같이 사용할 수 있습니다 .

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

나는 내 블로그에 다음과 같이 썼다 : http://www.pigeonsql.com/single-post/2016/12/13/Kill-all-connections-on-DB-by-Cursor


0
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
*/

-1

아래의 간단한 코드로 성공적으로 테스트했습니다.

USE [master]
GO
ALTER DATABASE [YourDatabaseName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

2
set SINGLE_USER이미 단일 활성 연결이있을 때 문제가있었습니다 .
ivan_pozdeev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.