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


72

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

なぜこうなった?

回答:


20

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

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

  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_whoと他のメタデータ(DMV)がすべてのセッションを表示すると思っていたでしょうが、他のセッションではどのような用途ですか?
tuseau

はい。通常、sp_whoを使用してすべてのアクティブ/非アクティブを表示するか、マスターデータベースからsysprocessesテーブルを照会する必要があります。非表示とは、アプリケーションサービスから再接続するプロセスを意味します。乾杯。
ユルシカ

1
これは複数の理由で時代遅れになっています:(1)古いスタイルの結合(2)後方互換性ビュー(3)単一のALTERが行うときにKILLコマンドの束を実行するためのカーソルと動的SQL(4)sp_dboptionなどの非推奨のプロシージャ
アーロンバートランド

1
残念ながら、これが質問に答えるとは思わない-質問者は、どうやって解決するのかではなく、なぜこれが起こっているのかを尋ねている。提供された答えは機能しますが、データベースを削除できない理由はまだわかりません。@AaronBertrandは「オブジェクトエクスプローラーでさえ犯人になる可能性がある」と述べましたが、これが実際に1つのデータベースの理由になりましたが、どうすればオブジェクトエクスプローラーであると断言できますか?
-LearnByReading

これにより、「KILLを使用して自分のプロセスを
強制終了

80

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

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

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

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

DROP DATABASE dbname;

1
あなたの答えをありがとう、これは働いた。しかし、私はこのソリューションで生きるのに苦労しています:このエラーのためにいくつかのデータベースを削除できないのはなぜですか?1年間触れられていないデータベースがいくつかあり、それらに接続されているプロセスまたは表向きのトランザクションはありません。潜在的なサービス、トランザクション、またはこれらのデータベースに接続されている何かを見つけるのに役立つヒントを教えてください。
-LearnByReading

1
実際、私がしなければならなかったのはUSE master、その時だけDROP DATABASE dbnameでした。どうやら必要なのは、dbを解放するために、他の何かを「使用」することだけです。
vapcguy

2
@vapcguyこれは、現在のクエリウィンドウが唯一の接続である場合にのみ当てはまります。これは通常はそうではありません(そして、それが私の答えが「接続されているSSMSのコピーではないことを確認する」理由です)。
アーロンバートランド

20

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

use master
go
drop database mydb
go

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


私は間違いなくマスターとつながっています。データベースを削除するためにsaとして接続する必要はありません。これはバグのように見えます-セッションを表示していないか、使用中のセッションがあると考えていますが、表示されていません。
tuseau

3
私はこれに気付いたばかりです-sqlcmdプロンプトからデータベースに設定されたコンテキストでドロップスクリプトを実行しようとしました!ドー
ジョニーラー14

18

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

...と仮定すると、もちろん、それがコミットされていないトランザクションをロールバックするためにOKです
swasheck

4
データベースを削除していますが、大丈夫だと思います。
georgiosd

1
これは私のために働いた!:)
レオナルドトリマルキ

5

私はこの状況に何度も直面していますが、以下は私がしていることです:

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

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

2

私にとって初めて働いた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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.