复制
- 打开SSMS
在新的查询窗口中输入以下内容
use <YourDatabase>;
go
- 转到对象资源管理器(SSMS),然后右键单击
<YourDatabase>
-> Tasks
->Take Offline
打开第二个新查询窗口,然后键入以下内容:
use <YourDatabase>;
go
将提示您以下消息:
消息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;
对于它的价值,您不需要对象资源管理器即可重现此错误。您只需要尝试相同操作的阻止请求(在这种情况下,使数据库脱机)。有关T-SQL中的三个步骤,请参见下面的屏幕截图:
您最有可能看到的是您的Object Explorer会话被另一个会话阻止(显示为blocking_session_id
)。该对象资源管理器会话将尝试获取X
数据库的排他锁()。在上述repro的情况下,对象资源管理器会话被授予了更新锁(U
),并尝试转换为互斥锁(X
)。它的wait_type为LCK_M_X
,被我们的会话阻止,该会话由第一个查询窗口表示(获取数据库上的use <YourDatabase>
共享锁(S
))。
然后,此错误来自另一个试图获取锁的会话,并且此错误消息导致拒绝会话以获取对尝试转换为其他状态(在这种情况下为在线状态)的数据库的访问到离线过渡)。
下次您该怎么办?
首先,不要惊慌,也不要开始删除数据库。您需要采取故障排除方法(与上面的诊断查询类似),以查明为什么看到了自己看到的东西。收到类似这样的消息,或者当出现“挂起”消息时,您应该自动假定并发性不足并开始深入研究阻塞(这sys.dm_tran_locks
是一个不错的开始)。
另外,我确实相信您最好在采取任何随机措施之前先找出问题的根源。不仅通过此操作,而且还适用于所有意外行为。知道是什么真正导致了您的问题,很明显这没什么大不了的。您基本上有一个阻塞链,并且父阻塞程序很可能刚刚发出了KILL
on,或者如果会话的请求是您不希望的,KILL
那么您可以等到它完成为止。无论哪种方式,您都具有在特定情况下(回滚或等待提交)做出正确而谨慎决定的知识。
另一件事值得注意,这就是为什么我总是选择T-SQL替代而不是GUI的原因之一。您确切地知道您正在使用T-SQL执行什么以及SQL Server在做什么。毕竟,您发出了明确的命令。当您使用GUI时,实际的T-SQL将成为一种抽象。在这种情况下,我查看了受阻的对象资源管理器试图使数据库脱机,事实是ALTER DATABASE <YourDatabase> SET OFFLINE
。没有回滚的尝试,这就是它无限期等待的原因。在您的情况下,如果您要回滚在该数据库上已锁定的会话,那么,ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
如果您最初确定回滚是可以的,则很可能已经足够了。