SQL Server şu anda kullanımda olduğu için <dbname> veritabanını bırakamıyor.


72

Bir veritabanını bırakmaya çalıştığımda, şu anda kullanımda olduğu için "veritabanı bırakılamıyor" dbname "hatası alıyorum. Ancak, çalıştırdığımda sp_who2, kesinlikle bu veritabanına bağlı oturum yok. Ayrıca veritabanını da ayarladım single_user mode with rollback immediate.

Bu neden oluyor?

Yanıtlar:


20

Kaldırmak istediğiniz db'deki veritabanı anlık görüntüleri gibi bağımlılıklarınızın olmadığından emin olun. Yine de, hata mesajı başka şekilde görünecekti. Veritabanınıza bağlanan hiçbir gizli işlem olmadığından emin misiniz? İyi bir yaklaşım, tüm oturumları öldüren bir komut dosyasını çalıştırmak ve veritabanını yeniden adlandırdıktan hemen sonra başka bir ada koymak ve ardından veritabanını bırakmak olacaktır.

bu seçime göre bir imleç oluşturun:

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

imlecin içindeki sorun:

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

imleç kapatılıp bırakıldıktan sonra:

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

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 

Kod için teşekkürler - işe yarayabilir. Anlamadığım şey, "gizli" bir oturum nedir? Sp_who'nun ve diğer meta verilerin (DMV'ler) tüm oturumları göstereceğini düşünürdüm , başkaları ne kullanıyorlardı?
tuseau

Evet, normal olarak sp_who aracılığıyla veya sysprocesses tablosunu master db'den sorgulayarak tüm aktif / aktif olmayanları görebilmelisiniz. Gizlediğimde, bir uygulama servisinden yeniden bağlanan bir işlemi kastediyorum. Şerefe.
yrushka

1
Bu, birçok nedenden dolayı eski haline getirilir: (1) eski tarz birleşimler (2) geriye dönük uyumluluk görünümleri (3), tek bir ALTER (4) sp_dboption gibi kullanımdan kaldırılmış prosedürler yapacağı zaman bir demet KILL komutunu çalıştırmak için bir imleç ve dinamik SQL.
Aaron Bertrand

1
Maalesef bunun soruyu yanıtladığını sanmıyorum - sorgulayıcı bunun neden olduğunu soruyor, nasıl çözüleceğini değil. Verilen cevap işe yarıyor, fakat hala beni bir veritabanını silmekten ne alıkoydu bilmiyorum. @AaronBertrand, aslında veritabanlarının BİR'inin nedeni olan "Object Explorer bile suçlu olabilir" den bahsetti, ancak bunun Object Explorer olduğundan nasıl emin olduğunu nasıl bilebilirdim?
LearnByReading

Bu bana "Kendi işleminizi öldürmek için KILL kullanamıyorum" hatası veriyor
nuander

80

Başka bir veritabanına bağlı bir oturum, veritabanınızı da etkileyen açık bir işleme sahip olabilir - sp_who2 yalnızca bir veritabanını gösterir. Ayrıca, SSMS'de açık olan Nesne Gezgini veya Nesne Gezgini Ayrıntıları gibi basit bir şey olabilir;

Çalışırken rahatsız etmeyin bulmak sorumludur oturumu; hepsini tek bir ifadeyle öldürün (ve bağlı olan SSMS kopyanızın olmadığından emin olun (örneğin, başka bir sorgu penceresi, Nesne Gezgini, vb.):

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

Şimdi, kullanıcı arayüzünü değil, DDL kullanarak bunu bırakabileceksiniz:

DROP DATABASE dbname;

1
Cevabınız için teşekkürler, bu işe yaradı. Ancak bu çözümle yaşamakta zorluk çekiyorum: neden bu hata nedeniyle bazı veritabanlarını bırakamıyorum? Bir yıl boyunca dokunulmamış bazı veritabanlarım var ve bunlara bağlı bir işlem ya da görünmez işlem yok. Potansiyel hizmetleri ya da işlemleri ya da bu veritabanlarına bağlı herhangi bir şeyi bulmama yardımcı olacak ipuçları verebilir misiniz?
LearnByReading

1
Aslında, tüm yapmak zorunda olduğunu USE master, sonra DROP DATABASE dbname. Görünüşe göre ihtiyacın olan tek şey db'yi serbest bırakmak için başka bir şeyi "kullanmak".
vapcguy

2
@vapcguy Bu, yalnızca geçerli sorgu pencereniz tek bağlantı ise geçerlidir. Bu genellikle durum böyle değildir (ve bu yüzden cevaplarım "ve" bağlı SSMS kopyanız olmadığından emin olun "demiştir).
Aaron Bertrand

20

DROPKomutu verdiğinizde mevcut veritabanınız nedir ? Bunu dene:

use master
go
drop database mydb
go

Ayrıca olarak bağlandığından emin olun save dboyorulana istediğiniz hangisi veritabanı üzerinde.


Kesinlikle efendiye bağlıyım. Veritabanını bırakmak için sa olarak bağlanmam gerekmiyordu. Bu bana bir hata gibi görünüyor - bir oturumu görüntülemiyor ya da kullanımda bir oturum olduğunu düşünüyor ama yok.
tuseau

3
Ben sadece bununla yakalandım - drop betiğini sqlcmd isteminden veri tabanına ayarlanmış bağlamda çalıştırmaya çalıştım! Doh
JonnyRaa 23:14

18

Kullanıcı arabirimini kullanırken ancak eylem için bir komut dosyası vermesini söylediğinde SSMS'nin ne yaptığını görmeye ne dersiniz? İşte DB'yi sağ tıklayıp Sil'i seçtiğinizde SSMS'nin yaptığı, ardından mevcut bağlantıları kapatmak için kutuyu işaretleyin:

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

... farz
edersek

4
Veritabanını düşürüyorsun, sanırım her şey yolunda.
georgiosd

1
Bu benim için çalıştı! :)
Leonardo Trimarchi

5

Bu durumla birçok kez karşılaştım ve aşağıda yaptığım şey:

Belirgin yöntemler işe yaramadığında ..... (sizin durumunuzdaki gibi):

Sysdatabases veritabanı kimliğini öğrenin.

Sonra yürütün - sp_lockbu, örnekteki tüm kilitleri spid ve dbid ile birlikte gösterir.

Çevrimdışıyken veya düşürmeye çalıştığınız dbid ile örümcekleri öldürün.

İşlem biraz manuel olsa da, aşağıdaki gibi otomatikleştirilebilir:

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

Benim için ilk kez çalışan StackOverflow ile ilgili gerçekten basit bir cevap buldum:

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

İşte bu cevaptan 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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.