it-swarm.asia

SQL Server Tidak Dapat menjatuhkan basis data <dbname> karena sedang digunakan ... tetapi tidak ada sesi yang ditampilkan

Ketika saya mencoba untuk menjatuhkan database saya mendapatkan kesalahan "Tidak bisa drop database" dbname "karena saat ini sedang digunakan". Namun, ketika saya menjalankan sp_who2, pasti tidak ada sesi yang terhubung ke database ini. Saya juga mengatur database ke single_user mode with rollback immediate.

Mengapa ini terjadi?

81
tuseau

Pastikan Anda tidak memiliki dependensi seperti snapshot basis data pada db yang ingin Anda hapus. Padahal, pesan kesalahan akan terlihat sebaliknya. Apakah Anda yakin tidak ada proses tersembunyi yang menghubungkan ke database Anda? Pendekatan yang baik adalah dengan menjalankan skrip yang membunuh semua sesi dan segera setelah mengubah nama database menjadi nama lain dan kemudian drop database.

buat kursor berdasarkan pada pilih ini:

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

masalah di dalam kursor:

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

setelah kursor ditutup dan tidak dialokasikan:

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

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
22
yrushka

Sesi yang terhubung ke basis data lain mungkin memiliki transaksi terbuka yang juga memengaruhi basis data Anda - sp_who2 hanya akan menampilkan satu basis data. Itu bisa juga sesuatu yang sederhana seperti Object Explorer atau Rincian Obyek Explorer terbuka di SSMS, yang lagi-lagi hanya akan menampilkan satu database di sp_who2.

Jangan repot-repot mencoba temukan sesi yang bertanggung jawab; bunuh saja semuanya dengan satu pernyataan (dan pastikan itu bukan salinan SSMS Anda yang terhubung, mis. jendela kueri lain, Object Explorer, dll.):

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

Sekarang Anda dapat menjatuhkannya, dan melakukannya menggunakan DDL, bukan UI:

DROP DATABASE dbname;
92
Aaron Bertrand

Apa basis data Anda saat ini ketika Anda mengeluarkan perintah DROP? Coba ini:

use master
go
drop database mydb
go

Pastikan juga Anda terhubung sebagai sa dan bukan dbo pada basis data apa pun yang ingin Anda jatuhkan.

20
Gaius

Bagaimana kalau hanya melihat apa yang dilakukan SSMS saat Anda menggunakan UI tetapi suruh untuk mengeluarkan skrip untuk tindakan? Inilah yang dilakukan SSMS ketika Anda mengklik kanan DB dan memilih Hapus, lalu centang kotak untuk menutup koneksi yang ada:

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

Saya telah menghadapi situasi ini berkali-kali dan di bawah inilah yang saya lakukan:

Ketika metode yang jelas tidak bekerja ..... (seperti dalam situasi Anda):

Cari tahu ID basis data dari sysdatabases.

Kemudian jalankan - sp_lock yang akan menampilkan semua kunci pada instance beserta spid dan dbid.

Bunuh spid dengan dbid yang sedang Anda coba offline atau jatuhkan.

Padahal, prosesnya sedikit manual, bisa otomatis seperti di bawah ini:

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

Menemukan jawaban yang sangat sederhana di StackOverflow yang berfungsi pertama kali untuk saya:

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

Inilah SQL dari jawaban itu:

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