SQL Server ไม่สามารถวางฐานข้อมูล <dbname> ได้เนื่องจากมีการใช้งานอยู่ ... แต่ไม่มีเซสชันปรากฏขึ้น


72

เมื่อฉันพยายามที่จะวางฐานข้อมูลฉันได้รับข้อผิดพลาด "ไม่สามารถวางฐานข้อมูล" dbname "เพราะมันกำลังใช้งานอยู่" อย่างไรก็ตามเมื่อฉันรันsp_who2ไม่มีการเชื่อมต่อเซสชันกับฐานข้อมูลนี้ single_user mode with rollback immediateฉันยังได้ตั้งฐานข้อมูลเพื่อ

ทำไมสิ่งนี้จึงเกิดขึ้น

คำตอบ:


20

ตรวจสอบให้แน่ใจว่าคุณไม่มีการพึ่งพาเช่นสแน็ปช็อตฐานข้อมูลบน db ที่คุณต้องการลบ แม้ว่าข้อความแสดงข้อผิดพลาดจะดูเป็นอย่างอื่น คุณแน่ใจหรือว่าไม่มีกระบวนการซ่อนเร้นที่เชื่อมต่อกับฐานข้อมูลของคุณ? แนวทางที่ดีคือการเรียกใช้สคริปต์ที่ฆ่าทุกเซสชันและทันทีหลังจากเปลี่ยนชื่อฐานข้อมูลเป็นชื่ออื่นแล้วปล่อยฐานข้อมูล

สร้างเคอร์เซอร์ตามการเลือกนี้:

  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 และ metadata อื่น ๆ (DMVs) จะแสดงเซสชันทั้งหมดและพวกเขาใช้อะไรอยู่
tuseau

ได้ตามปกติคุณควรจะสามารถดูสถานะ active / nonactive ทั้งหมดผ่าน sp_who หรือสอบถามตาราง sysprocesses จาก master db โดยการซ่อนฉันหมายถึงกระบวนการที่เชื่อมต่อใหม่จากบริการแอปพลิเคชัน ไชโย
yrushka

1
สิ่งนี้เป็นของเก่าด้วยเหตุผลหลายประการ: (1) การรวมแบบเก่า (2) มุมมองความเข้ากันได้แบบย้อนหลัง (3) เคอร์เซอร์และ SQL แบบไดนามิกเพื่อเรียกใช้คำสั่ง KILL จำนวนมากเมื่อ ALTER เดียวจะทำ (4) โพรซีเดอร์
Aaron Bertrand

1
น่าเสียดายที่ฉันไม่คิดว่านี่เป็นคำตอบของคำถามผู้ถามถามว่าทำไมสิ่งนี้ถึงเกิดขึ้นไม่ใช่วิธีการแก้ปัญหา คำตอบนั้นได้ผล แต่ฉันก็ยังไม่รู้ว่าอะไรทำให้ฉันไม่สามารถลบฐานข้อมูลได้ @AaronBertrand พูดถึง "แม้แต่ Object Explorer อาจเป็นผู้ร้าย" ซึ่งจริง ๆ แล้วเป็นเหตุผลสำหรับหนึ่งในฐานข้อมูล แต่ฉันจะบอกได้อย่างไรว่าเป็น Object Explorer แน่นอน?
LearnByReading

นี้จะช่วยให้ฉันข้อผิดพลาด "ไม่สามารถใช้ฆ่าฆ่ากระบวนการของคุณเอง"
nuander

80

เซสชันที่เชื่อมต่อกับฐานข้อมูลอื่นอาจมีธุรกรรมเปิดที่มีผลต่อฐานข้อมูลของคุณด้วย - sp_who2 จะแสดงฐานข้อมูลเดียวเท่านั้น มันอาจเป็นอะไรที่ง่ายอย่างเช่น Object Explorer หรือ Object Explorer Details ที่เปิดใน SSMS ซึ่งจะแสดงเพียงหนึ่งฐานข้อมูลใน sp_who2

ไม่ต้องพยายามหาเซสชันที่รับผิดชอบ เพียงฆ่าพวกเขาทั้งหมดด้วยคำสั่งเดียว (และตรวจสอบให้แน่ใจว่าไม่ใช่สำเนา SSMS ของคุณที่เชื่อมต่ออยู่เช่นหน้าต่างแบบสอบถามอื่น Object Explorer ฯลฯ ):

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

ตอนนี้คุณจะสามารถวางและใช้ DDL ไม่ใช่ UI:

DROP DATABASE dbname;

1
ขอบคุณสำหรับคำตอบของคุณสิ่งนี้ใช้ได้ผล แต่ฉันมีปัญหาในการใช้งานโซลูชันนี้: เหตุใดฉันจึงไม่สามารถลบฐานข้อมูลบางส่วนได้เนื่องจากข้อผิดพลาดนี้ ฉันมีฐานข้อมูลบางตัวที่ไม่ได้สัมผัสเป็นเวลาหนึ่งปีและไม่มีกระบวนการหรือธุรกรรมที่ชัดเจนที่เชื่อมต่อกับพวกเขา คุณสามารถให้คำแนะนำเพื่อช่วยค้นหาบริการที่เป็นไปได้หรือธุรกรรมหรือสิ่งใดก็ตามที่เชื่อมต่อกับฐานข้อมูลเหล่านี้
LearnByReading

1
จริงๆแล้วสิ่งที่ผมต้องทำคือแล้วUSE master DROP DATABASE dbnameเห็นได้ชัดว่าทั้งหมดที่จำเป็นคือเพียง "ใช้" อย่างอื่นเพื่อปล่อย db
vapcguy

2
@vapcguy นั่นเป็นจริงหากหน้าต่างแบบสอบถามปัจจุบันของคุณคือการเชื่อมต่อเท่านั้น นี่ไม่ใช่กรณี (และเป็นสาเหตุที่คำตอบของฉันระบุ "และตรวจสอบให้แน่ใจว่าไม่ใช่สำเนา SSMS ของคุณที่เชื่อมต่อ")
Aaron Bertrand

20

ฐานข้อมูลปัจจุบันของคุณคืออะไรเมื่อคุณออกDROPคำสั่ง ลองสิ่งนี้:

use master
go
drop database mydb
go

ตรวจสอบให้แน่ใจว่าคุณเชื่อมต่อเป็นsaและไม่ได้dboอยู่ในฐานข้อมูลใดที่คุณต้องการวาง


ฉันเชื่อมต่อกับอาจารย์อย่างแน่นอน ฉันไม่ควรเชื่อมต่อเป็น sa เพื่อปล่อยฐานข้อมูล นี่ดูเหมือนว่าฉันจะเป็นแมลง - มันไม่ได้แสดงเซสชั่นหรือคิดว่ามันมีการใช้งานเซสชั่น แต่ไม่มี
tuseau

3
ฉันเพิ่งถูกจับได้ด้วยสิ่งนี้ - พยายามรันสคริปต์ดร็อปโดยบริบทตั้งค่าฐานข้อมูลจากพรอมต์ sqlcmd! Doh
JonnyRaa

18

ลองดูว่า SSMS ทำอะไรเมื่อคุณใช้ UI แต่บอกให้ออกสคริปต์สำหรับการกระทำ นี่คือสิ่งที่ 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

... สมมติว่าเป็นเรื่องตกลงที่จะย้อนกลับการทำธุรกรรมที่ไม่มีข้อผูกมัด
ยุด

4
คุณกำลังทิ้งฐานข้อมูลฉันจะถือว่ามันไม่เป็นไร
georgiosd

1
สิ่งนี้ได้ผลสำหรับฉัน! :)
Leonardo Trimarchi

5

ฉันได้เผชิญกับสถานการณ์นี้หลายครั้งและที่ต่ำกว่าคือสิ่งที่ฉันทำ

เมื่อวิธีการที่ชัดเจนไม่ทำงาน ..... (เช่นเดียวกับในสถานการณ์ของคุณ):

ค้นหารหัสฐานข้อมูลจากฐานข้อมูล

จากนั้นดำเนินการ - sp_lockซึ่งจะแสดงการล็อกทั้งหมดบนอินสแตนซ์พร้อมกับ spid และ dbid

ฆ่า spids ด้วย dbid ที่คุณพยายามออฟไลน์หรือดรอป

แม้ว่ากระบวนการนี้เป็นคู่มือเล็กน้อยก็สามารถเป็นไปโดยอัตโนมัติดังต่อไปนี้:

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.