如果在数据库中使用查询通知,还原或恢复可能会失败或需要很长时间

本文可帮助你解决在数据库中使用查询通知时还原或恢复可能会失败或花费很长时间的问题。

原始产品版本:SQL Server
原始 KB 编号: 2483090

症状

对于为查询通知订阅配置的数据库,你可能会注意到以下一个或多个症状:

  • 症状 1:如果在还原操作期间指定 了NEW_BROKER 选项,则从其备份还原数据库可能会失败并显示 1205 错误消息。 此外,将在 SQL Server 的 Errorlog 文件夹中生成转储文件。

  • 症状 2:从备份还原数据库失败,数据库脱机。 此外,SQL Server错误日志中记录了以下消息:

    <Datetime> spid61 错误: 9768,严重性: 16,状态: 1。
    <Datetime> spid61 在与远终结点交换凭据之前,删除了与安全会话关联的数据库用户。 在创建对话时避免使用 DROP USER。
    <Datetime> spid61 无法检查数据库“5”中挂起的查询通知,因为在打开数据库时出现以下错误:“与远端终结点交换凭据之前,与安全会话关联的数据库用户已被删除。 在创建对话时避免使用 DROP USER。 查询通知订阅清理操作失败。 有关详细信息,请参阅以前的错误。'。
    <Datetime> spid61 错误: 9001,严重性: 16,状态: 5。
    <Datetime> spid61 数据库“Test”的日志不可用。 检查事件日志中是否有相关的错误消息。 解决任何错误并重启数据库。
    <Datetime> spid61 错误: 3314,严重性: 21,状态: 4。
    <Datetime> spid61 在数据库“Test”中撤消记录的操作期间,日志记录 ID (1835:7401:137) 发生错误。 通常,特定失败以前在 Windows 事件日志服务中记录为错误。 从备份还原数据库或文件,或修复数据库。

    注意

    在数据库的恢复阶段,可能会遇到问题。 数据库联机、服务器重启等时,也会在数据库上运行恢复。

  • 症状 3:从数据库备份还原数据库可能需要很长时间,并且类似于以下内容的消息记录在错误日志SQL Server:

    日期时间 SPID 查询通知传递无法在对话框“{ 对话 ID }.”上发送消息。 传递失败,通知“?<qn:QueryNotification xmlns:qn=“https://schemas.microsoft.com/SQL/Notifications/QueryNotification” id=“2881” type=“change” source=“database” info=“restart” database_id=“7” sid=“0x010500000000000515000000FA48F22A6990BA52422C73DFF9030000”><qn:Message>4a4c696b-645c-40fd-bfef-4f2bc7c599b4;eb99973e-3cc9-4c7e-b4b9-47d8cf590c43</qn:Message></qn:QueryNotification>',因为 Service Broker 中出现以下错误:“找不到会话句柄”<会话处理程序>”。

    注意

    在数据库的恢复阶段,可能会遇到问题。 数据库联机、服务器重启等时,也会在数据库上运行恢复。

原因

症状 1 的原因:在还原操作期间指定NEW_BROKER选项时,SQL Server尝试截断所有与 Service Broker 相关的表。 截断需要在截断对象上SCH_M锁。 因此,main事务在 sysdesend 上保留SCH_M锁。 恢复或还原数据库时,默认情况下SQL Server尝试触发所有未完成的查询通知,这要求在 sysdesend 表中插入行 (消息) 。 此操作需要对表使用SCH_S锁。 但是,此操作发生在不同的事务上,并且第一个事务持有的SCH_M锁阻止了获取SCH_S锁的尝试。 因此,执行还原的线程现在在它拥有的资源上被阻止,这种情况称为自死锁。 死锁监视器检测到死锁,线程终止,从而终止还原操作。

有关锁的详细信息,请参阅 锁定模式。 “症状”部分讨论的其他症状是由于以下解决方法部分中提到的修复文章中所述的已知问题引起的。

解决方案

症状 1 的解决方法:在尝试还原操作之前,可以通过启用会话级别跟踪标志 9109 来解决此问题。 示例脚本如下所示:

dbcc traceon (9109)
go
RESTORE DATABASE [Test] 
FROM DISK = N'C:\TestBackup.bak' WITH FILE = 1, 
MOVE N'test_Data' TO N'C:\test.mdf', 
MOVE N'test_Log' TO N'C:\test_1.ldf', 
NOUNLOAD, 
STATS = 1, 
NEW_BROKER
go
dbcc traceoff (9109)
go

注意

数据库完全还原或恢复后,强烈建议检查,以确保触发查询通知。 实现此目的的最简单方法是将数据库的状态更改为“只读”,然后将其改回“读写”。 可以为此检查的一些其他方法包括分离和重新附加数据库、重启SQL Server等。

还可以通过在还原操作上不指定 NEW_BROKER 选项来完全避免此问题,而是在还原数据库后将 与 NEW_BROKER 选项一ALTER DATABASE起使用。

有关详细信息,请参阅 DBCC TRACEON - 跟踪标志 (Transact-SQL)