データベースを削除しようとすると、「データベース "dbname"は現在使用中なので削除できません」というエラーが表示されます。ただし、sp_who2
を実行すると、このデータベースに接続されているセッションはありません。また、データベースをsingle_user mode with rollback immediate
に設定しました。
なんでこんなことが起こっているの?
削除するデータベースにデータベーススナップショットなどの依存関係がないことを確認してください。ただし、エラーメッセージは別の方法で表示されます。データベースに接続している非表示のプロセスがないことを確信していますか?すべてのセッションを強制終了するスクリプトを実行し、データベースの名前を別の名前に変更した直後にデータベースを削除することをお勧めします。
この選択に基づいてカーソルを作成します。
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
別のデータベースに接続されているセッションには、データベースにも影響する開いているトランザクションがある可能性があります。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;
DROP
コマンドを発行したときの現在のデータベースは何ですか?これを試して:
use master
go
drop database mydb
go
また、ドロップするデータベースにsa
ではなくdbo
として接続していることを確認してください。
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
私は何度もこの状況に直面しており、以下が私がすることです。
明らかな方法が機能しない場合.....(あなたの状況と同じように):
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
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)