“数据库正在转换”错误

M.A*_*Ali 13 sql-server backup sql-server-2008-r2 restore

今天,我试图在现有数据库上恢复数据库,我只需在 SSMS --> 任务 --> 脱机中右键单击该数据库,以便我可以恢复数据库。

一个小的弹出窗口出现并显示Query Executing.....了一段时间,然后抛出一个错误说Database is in use cannot take it offline。我从中收集了一些与该数据库的活动连接,因此我尝试执行以下查询

USE master
GO
ALTER DATABASE My_DatabaseName
SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
Run Code Online (Sandbox Code Playgroud)

再次在这一点上 SSMS 显示Query Executing.....了一段时间,然后抛出以下错误:

Msg 5061, Level 16, State 1, Line 1
ALTER DATABASE failed because a lock could not be placed on database 'My_DatabaseName'. Try again later.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.
Run Code Online (Sandbox Code Playgroud)

在此之后,我无法通过 SSMS 连接到数据库。当我尝试使用 SSMS 将其离线时,它抛出了一个错误:

Database is in Transition. Try later .....
Run Code Online (Sandbox Code Playgroud)

在这一点上,我根本无法触摸数据库,我尝试过的任何内容都返回了相同的错误消息Database is in Transition

我在谷歌上阅读了一些人们遇到类似问题的问题,他们建议关闭 SSMS 并再次打开它,我也是如此,由于它只是一个开发服务器,我只是使用 SSMS 删除了数据库并在新数据库上恢复。

我的问题是可能导致这种情况的原因是什么?以及我如何才能避免将来发生这种情况,如果我将来遇到相同的情况,除了删除整个数据库之外还有其他方法可以修复它吗???

谢谢

Tho*_*ger 24

再现

  1. 打开 SSMS
  2. 在新的查询窗口中输入以下内容

    use <YourDatabase>;
    go
    
    Run Code Online (Sandbox Code Playgroud)
  3. 转到对象资源管理器 (SSMS) 并右键单击<YourDatabase>-> Tasks->Take Offline
  4. 打开第二个新查询窗口并键入以下内容:

    use <YourDatabase>;
    go
    
    Run Code Online (Sandbox Code Playgroud)

您将收到以下消息提示:

消息 952,级别 16,状态 1,第 1 行
数据库“TestDb1”正在转换中。稍后尝试该语句。

发生这种情况的原因可以从与以下类似的诊断查询中找到:

select
    l.resource_type,
    l.request_mode,
    l.request_status,
    l.request_session_id,
    r.command,
    r.status,
    r.blocking_session_id,
    r.wait_type,
    r.wait_time,
    r.wait_resource,
    request_sql_text = st.text,
    s.program_name,
    most_recent_sql_text = stc.text
from sys.dm_tran_locks l
left join sys.dm_exec_requests r
on l.request_session_id = r.session_id
left join sys.dm_exec_sessions s
on l.request_session_id = s.session_id
left join sys.dm_exec_connections c
on s.session_id = c.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st
outer apply sys.dm_exec_sql_text(c.most_recent_sql_handle) stc
where l.resource_database_id = db_id('<YourDatabase>')
order by request_session_id;
Run Code Online (Sandbox Code Playgroud)

无论如何,您不需要对象资源管理器来重现此错误。您只需要一个尝试相同操作的阻塞请求(在这种情况下,使数据库脱机)。有关 T-SQL 中的三个步骤,请参见以下屏幕截图:

在此处输入图片说明

您最有可能看到的是您的对象资源管理器会话被另一个会话阻止(由 显示blocking_session_id)。该对象资源管理器会话将尝试获取X数据库的排它锁 ( )。在上述重现的情况下,对象资源管理器会话被授予更新锁 ( U) 并尝试转换为排它锁 ( X)。它的 wait_type 为LCK_M_X,被我们的会话阻塞,该会话由第一个查询窗口表示(获取数据库上的use <YourDatabase>共享锁 ( S))。

然后这个错误来自另一个试图获得锁的会话,这个错误消息导致拒绝会话访问试图转换到不同状态的数据库(在这种情况下,状态为 online到离线过渡)。

下次应该怎么做?

首先,不要惊慌不要开始删除数据库。你需要采取的故障排除方法(与像上面的一个类似的诊断查询)来找出为什么你看到你看到的。对于这样的消息,或者当某些东西出现“挂起”时,您应该自动假设缺乏并发性并开始深入研究阻塞(这sys.dm_tran_locks是一个好的开始)。

作为旁注,我确实相信您最好在采取任何随机行动之前找出问题的根源。不仅适用于此操作,而且适用于您不期望的所有行为。知道是什么真正导致了您的问题,很明显这真的没什么大不了的。你基本上有一个阻塞链,父阻塞器是你最有可能刚刚发布的东西KILL,或者如果它是一个你不想要的会话请求,KILL那么你可以等到它完成。无论哪种方式,您都会有知识来根据您的特定场景(回滚或等待提交)做出正确和谨慎的决定。

另一件值得注意的事情是,这就是我总是选择 T-SQL 替代方案而不是 GUI 的原因之一。您确切地知道您正在使用 T-SQL 执行什么以及 SQL Server 在做什么。毕竟,您发出了显式命令。当您使用 GUI 时,实际的 T-SQL 将是一个抽象。在这种情况下,我查看了被阻止的对象资源管理器尝试使数据库脱机的尝试,结果是ALTER DATABASE <YourDatabase> SET OFFLINE. 没有尝试回滚,这就是它无限期等待的原因。在您的情况下,如果您想回滚锁定该数据库的会话,ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE如果您最初确定回滚没问题,那么您很可能就足够了。


小智 5

只需关闭 SQL Server Management Studio (SSMS) 并重新打开即可为我解决此问题。