Máy chủ SQL không thể hủy cơ sở dữ liệu <dbname> vì hiện tại nó đang được sử dụng nhưng không có phiên nào được hiển thị


72

Khi tôi cố gắng hủy cơ sở dữ liệu, tôi gặp lỗi "Không thể hủy cơ sở dữ liệu" dbname "vì hiện tại nó đang được sử dụng". Tuy nhiên, khi tôi chạy sp_who2, chắc chắn không có phiên nào được kết nối với cơ sở dữ liệu này. Tôi cũng đã thiết lập cơ sở dữ liệu single_user mode with rollback immediate.

Tại sao chuyện này đang xảy ra?

Câu trả lời:


20

Hãy chắc chắn rằng bạn không có các phụ thuộc như ảnh chụp nhanh cơ sở dữ liệu trên db mà bạn muốn xóa. Mặc dù, thông báo lỗi sẽ nhìn khác. Bạn có chắc chắn rằng không có quá trình ẩn nào đang kết nối với cơ sở dữ liệu của bạn không? Một cách tiếp cận tốt sẽ là chạy một tập lệnh giết tất cả các phiên và ngay sau khi đổi tên cơ sở dữ liệu thành tên khác và sau đó bỏ cơ sở dữ liệu.

tạo một con trỏ dựa trên lựa chọn này:

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

vấn đề bên trong con trỏ:

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

sau khi con trỏ được đóng lại và giải phóng:

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

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 

Cảm ơn mã - có thể làm việc. Điều tôi không hiểu là, phiên "ẩn" là gì? Tôi đã nghĩ rằng sp_who và các siêu dữ liệu khác (DMV) sẽ hiển thị tất cả các phiên, những người khác sử dụng chúng là gì?
tuseau

Có thông thường, bạn sẽ có thể thấy tất cả hoạt động / không hoạt động thông qua sp_who hoặc truy vấn bảng sys Processes từ master db. Bằng cách ẩn tôi có nghĩa là một quá trình kết nối lại từ một dịch vụ ứng dụng. Chúc mừng.
yrushka

1
Điều này được cổ xưa vì nhiều lý do: (1) tham gia kiểu cũ (2) chế độ xem tương thích ngược (3) con trỏ và SQL động để chạy một loạt các lệnh KILL khi một ALTER duy nhất sẽ thực hiện (4) các thủ tục không dùng nữa như sp_dboption.
Aaron Bertrand

1
Thật không may, tôi không nghĩ rằng điều này trả lời câu hỏi - người hỏi đang hỏi tại sao điều này xảy ra chứ không phải làm thế nào để giải quyết. Câu trả lời được cung cấp hoạt động, nhưng tôi vẫn không biết điều gì ngăn tôi xóa cơ sở dữ liệu. @AaronBertrand đã đề cập "ngay cả Object Explorer cũng có thể là thủ phạm" thực sự là lý do cho MỘT trong các cơ sở dữ liệu, nhưng làm thế nào tôi có thể nói đó là Object Explorer chắc chắn?
Tìm hiểu

điều này mang đến cho tôi lỗi "Không thể sử dụng KILL để giết quá trình của chính bạn"
nuander

80

Một phiên được kết nối với cơ sở dữ liệu khác có thể có giao dịch mở cũng ảnh hưởng đến cơ sở dữ liệu của bạn - sp_who2 sẽ chỉ hiển thị một cơ sở dữ liệu. Nó cũng có thể là một cái gì đó đơn giản như Object Explorer hoặc Object Explorer Chi tiết mở trong SSMS, một lần nữa sẽ chỉ hiển thị một cơ sở dữ liệu trong sp_who2.

Đừng bận tâm cố gắng tìm phiên có trách nhiệm; chỉ cần giết tất cả chúng bằng một câu lệnh (và đảm bảo rằng đó không phải là bản sao SSMS của bạn được kết nối, ví dụ: cửa sổ truy vấn khác, Object Explorer, v.v.):

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

Bây giờ bạn sẽ có thể loại bỏ nó và thực hiện điều đó bằng DDL, không phải UI:

DROP DATABASE dbname;

1
Cảm ơn câu trả lời của bạn, điều này đã làm việc. Nhưng tôi chỉ gặp khó khăn khi sống với giải pháp này: tại sao tôi không thể bỏ một số cơ sở dữ liệu do lỗi này? Tôi có một số cơ sở dữ liệu đã không được liên lạc trong một năm và không có quá trình hoặc giao dịch phô trương nào được kết nối với chúng. Bạn có thể cho tôi một số gợi ý để giúp tôi tìm các dịch vụ tiềm năng hoặc giao dịch hoặc bất kỳ thứ gì được kết nối với các cơ sở dữ liệu này không?
Tìm hiểu

1
Thật ra, tất cả những gì tôi phải làm là USE master, sau đó DROP DATABASE dbname. Rõ ràng tất cả những gì cần thiết là chỉ "sử dụng" thứ khác, để giải phóng db.
vapcguy

2
@vapcguy Điều đó chỉ đúng nếu cửa sổ truy vấn hiện tại của bạn là kết nối duy nhất. Đây không phải là trường hợp điển hình (và đó là lý do tại sao câu trả lời của tôi nêu rõ "và đảm bảo rằng đó không phải là bản sao SSMS của bạn được kết nối").
Aaron Bertrand

20

Cơ sở dữ liệu hiện tại của bạn là gì khi bạn ban hành DROPlệnh? Thử đi:

use master
go
drop database mydb
go

Ngoài ra, hãy chắc chắn rằng bạn được kết nối như savà không phải dbotrên bất kỳ cơ sở dữ liệu nào bạn muốn thả.


Tôi chắc chắn đã kết nối với chủ. Tôi không nên kết nối như sa để thả cơ sở dữ liệu. Điều này đối với tôi giống như một lỗi - nó không hiển thị một phiên hoặc nó nghĩ rằng có một phiên được sử dụng nhưng không có.
tuseau

3
Tôi vừa bị bắt gặp với điều này - đã cố chạy kịch bản thả với bối cảnh được đặt thành cơ sở dữ liệu từ dấu nhắc sqlcmd! Doh
JonnyRaa

18

Làm thế nào về việc chỉ nhìn thấy những gì SSMS làm khi bạn sử dụng UI nhưng bảo nó phát hành một kịch bản cho hành động? Dưới đây là những gì SSMS làm khi bạn nhấp chuột phải vào DB và chọn Xóa, sau đó chọn hộp để đóng các kết nối hiện có:

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

... giả sử, tất nhiên, bạn có thể quay lại các giao dịch không được cam kết
swasheck

4
Bạn đang bỏ cơ sở dữ liệu, tôi sẽ cho rằng nó khá ổn.
georgiosd

1
Điều này làm việc cho tôi! :)
Leonardo Trimarchi

5

Tôi đã phải đối mặt với tình huống này nhiều lần và dưới đây là những gì tôi làm:

Khi các phương thức rõ ràng không hoạt động ..... (giống như trong tình huống của bạn):

Tìm ra ID cơ sở dữ liệu từ cơ sở dữ liệu sysdat.

Sau đó thực thi - sp_lockđiều đó sẽ hiển thị tất cả các khóa trên cá thể cùng với spid và dbid.

Giết các spids với dbid mà bạn đang cố gắng ngoại tuyến hoặc thả.

Mặc dù, quá trình này là một chút thủ công, nó có thể được tự động hóa như sau:

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

Tìm thấy câu trả lời thực sự đơn giản trên StackOverflow lần đầu tiên làm việc với tôi:

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

Đây là SQL từ câu trả lời đó:

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.