症状
在 Microsoft SQL Server 2012 或 Microsoft SQL Server 2014 中使用数据库镜像时,你可能会遇到断言条件,并且数据库镜像进入 "已暂停" 状态。
原因
出现此问题的原因是,在分配新页面时,SQL Server 在新页面上获得 X 锁。 SQL Server 将在锁请求中放置新页面所属的 hobt_id (堆或 B 树 ID)。 但是,SQL Server 无法将 hobt_id 放入镜像日志中,并且会导致主映像和镜像之间的不同锁行为。这可以详细说明,如下所示:
-
T1 在页 P1 上保留一个 IX 锁。
-
T2 在 P1 上执行页拆分,分配新的页面 P2,在此处使用系统事务 TX,它拥有 P2 上的 X 锁。 此处 SQL Server 未将 hobt_id 放入镜像日志中。
-
TX 执行 T1 的锁定迁移,将 IX 锁从 P1 移动到 P2。
-
TX 已提交,现在 T2 可以使用页面 P2,并且 T2 在页面 P2 上获取另一个 IX 锁。
-
T1 已提交,现在 T2 是在 P2 上保留 IX 锁的唯一一个人。
-
在执行大量插入操作后,在主映像上,T2 将释放 P2 上的 IX,但在镜像中,在锁升级期间,T2 未释放 IX 锁。
-
删除大量内容后,页面 P2 将变为空且已释放。
-
T3 需要新页面,并且在分配 P2 时需要一个 X 锁,但在镜像上,此步骤由于步骤6而失败。
在镜像中,步骤6不会释放 IX 锁,因为锁块中的 hobt_id 不正确。 此错误的 hobt_id 在步骤2中出现,因此 SQL Server 不会将 hobt_id 放入镜像日志中。通常你看不到任何问题,因为步骤2中的 TX 非常短,并且将在提交时释放包含不正确的 hobt_id 的锁块。 但是,由于 step3 和以下步骤(4和5)中的锁定迁移,此锁定块包含不正确的 hobt_id 会保留,最后导致该问题。 主文件不存在此问题,因为它在步骤2中使用了正确的 hobt_id。 但日志记录没有正确的 hobt_id。
解决方案
在 SQL Server 的以下累积更新中,此问题首先已修复。
SQL Server 2014 的累积更新1 /en-us/help/2931693
SQL Server 2012 SP1 的累积更新9 /en-us/help/2931078
SQL Server 的每个新的累积更新均包含以前的累积更新中包含的所有修补程序和所有安全修补程序。 查看 SQL Server 的最新累积更新:
解决方法
若要解决此问题,请重新初始化镜像以结束暂停的状态。
状态
Microsoft 已确认这是在“适用范围”部分中列出的 Microsoft 产品存在的问题。