web-dev-qa-db-ja.com

SQL Serverはデータベース<dbname>を削除できません。現在使用中です...セッションは表示されません

データベースを削除しようとすると、「データベース "dbname"は現在使用中なので削除できません」というエラーが表示されます。ただし、sp_who2を実行すると、このデータベースに接続されているセッションはありません。また、データベースをsingle_user mode with rollback immediateに設定しました。

なんでこんなことが起こっているの?

81
tuseau

削除するデータベースにデータベーススナップショットなどの依存関係がないことを確認してください。ただし、エラーメッセージは別の方法で表示されます。データベースに接続している非表示のプロセスがないことを確信していますか?すべてのセッションを強制終了するスクリプトを実行し、データベースの名前を別の名前に変更した直後にデータベースを削除することをお勧めします。

この選択に基づいてカーソルを作成します。

  select  d.name , convert (smallint, req_spid) As spid
      from master.dbo.syslockinfo l, 
           master.dbo.spt_values v,
           master.dbo.spt_values x, 
           master.dbo.spt_values u, 
           master.dbo.sysdatabases d
      where   l.rsc_type = v.number 
      and v.type = 'LR' 
      and l.req_status = x.number 
      and x.type = 'LS' 
      and l.req_mode + 1 = u.number
      and u.type = 'L' 
      and l.rsc_dbid = d.dbid 
      and rsc_dbid = (select top 1 dbid from 
                      master..sysdatabases 
                      where name like 'my_db')

カーソル内の問題:

SET @kill_process =  'KILL ' + @spid      
            EXEC master.dbo.sp_executesql @kill_process
                   PRINT 'killed spid : '+ @spid

カーソルが閉じられ、割り当てが解除された後:

sp_dboption 'my_db', 'single user', 'TRUE'

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
22
yrushka

別のデータベースに接続されているセッションには、データベースにも影響する開いているトランザクションがある可能性があります。sp_who2は1つのデータベースのみを表示します。また、SSMSで開かれたオブジェクトエクスプローラーまたはオブジェクトエクスプローラーの詳細のように単純なものにすることもできます。

find責任のあるセッションにしようとしないでください。 1つのステートメントですべてを強制終了します(接続されているのがSSMSのコピーではないことを確認してください(たとえば、別のクエリウィンドウ、オブジェクトエクスプローラーなど))。

USE master;
GO
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

これで、UIをドロップするのではなく、DDLを使用してドロップできるようになります。

DROP DATABASE dbname;
92
Aaron Bertrand

DROPコマンドを発行したときの現在のデータベースは何ですか?これを試して:

use master
go
drop database mydb
go

また、ドロップするデータベースにsaではなくdboとして接続していることを確認してください。

20
Gaius

UIを使用するときにSSMSが何をするかを確認するだけで、アクションのスクリプトを発行するように指示するのはどうでしょうか。 DBを右クリックして[削除]を選択し、チェックボックスをオンにして既存の接続を閉じると、SSMSは次のようになります。

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'yourdbname'
GO

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

USE [master]
GO

DROP DATABASE [yourdbname]
GO
18
Thiago Silva

私は何度もこの状況に直面しており、以下が私がすることです。

明らかな方法が機能しない場合.....(あなたの状況と同じように):

SysdatabasesからデータベースIDを調べます。

次に、-sp_lockを実行します。これにより、spidとdbidとともにインスタンスのすべてのロックが表示されます。

オフラインまたは削除しようとしているdbidでspidを強制終了します。

ただし、プロセスは少し手動ですが、以下のように自動化できます。

IF OBJECT_ID('tempdb.dbo.#temp', 'U') IS NOT NULL
  DROP TABLE #temp;
create table #temp (spid int
                , dbid int
                ,ObjId bigint
                , IndId bigint
                ,Type varchar(5)
                ,resource varchar(max)
                ,Mode varchar(5)
                ,status varchar(10));
declare @dbid int
select @dbid =DB_ID(db_name())

insert into #temp
exec sp_lock

select * from #temp
where dbid = @dbid
5
Kin Shah

StackOverflowで私にとって初めて機能する本当に簡単な答えが見つかりました:

https://stackoverflow.com/a/7469167/261405

これがその回答のSQLです。

DECLARE @DatabaseName nvarchar(50)
SET @DatabaseName = N'YOUR_DABASE_NAME'

DECLARE @SQL varchar(max)

SELECT @SQL = COALESCE(@SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(@DatabaseName) AND SPId <> @@SPId

--Use this to see results
SELECT @SQL 
--Uncomment this to run it
--EXEC(@SQL)
3
Adrian Carr