如何防止 SELECT 上的分区列存储死锁

Cyn*_*ker 10 sql-server deadlock partitioning columnstore sql-server-2016

我在 SQL Server 2016 中有三个聚集列存储索引 (CCI) 表。所有这些 CCI 都在相同的分区方案中,基于租户 ID。最近,不一致的是,我在从连接到这些表的简单选择语句上遇到了死锁。死锁的示例查询:

SELECT  TOP 33 r.tenantid
FROM    Table_r r
        INNER JOIN Table_cm cm ON r.MyKey=cm.MyKey 
        INNER JOIN Table_pe pe ON r.MyKey=pe.MyKey 
WHERE   r.TenantId = 69
        AND pe.TenantId = 69
        AND cm.TenantId = 69
Run Code Online (Sandbox Code Playgroud)

错误信息:

事务(进程 ID 56)在与另一个进程的通用可等待对象资源上发生死锁,并已被选为死锁受害者。重新运行事务。

线索:

  • 如果查询使用除 CCI 之外的另一个索引,它不会死锁。
  • 如果我删除三个租户 ID 过滤器中的两个,它不会死锁。
  • 如果我选择前 32 位或更低,它不会死锁。
  • 如果我添加 OPTION (MAXDOP 1) 它不会死锁。
  • 我可以在我的乱码 PROD 副本、PROD READ-ONLY Secondary 和 PROD 本身中重现这一点。
  • 我无法在 DEV 或 INT 中重现这种行为。
  • 如果我将 WITH(NOLOCK) 添加到所有 3 个表连接,它仍然会死锁
  • 查询本身会死锁。当没有其他活动进程时,它将死锁。
  • 没有并行性的查询计划不会死锁

死锁 xml 在这里

我们的生产版本:

Microsoft SQL Server 2016 (SP2-CU5) (KB4475776) - 13.0.5264.1 (X64) 2019 年 1 月 10 日 18:51:38 版权所有 (c) Microsoft Corporation Enterprise Edition(64 位),Windows Server 2012 R2 Standard 6.3(Build 9600) :)(管理程序)

如何防止此查询出现死锁?

Jos*_*ell 10

由于您使用的是 SQL Server 2016,因此值得一提的是,对于涉及列存储索引的并行死锁,至少有一个公共错误修复:

修复: 对 SQL Server 2016 和 2017 中的聚集列存储索引运行并行查询时发生死锁

(感谢Denis Rubashkin最初提供链接)

这是作为 SP1 CU7 的一部分发布的。如果你不符合那个 CU,你应该试一试。此修复程序也将包含在 SP2(任何 CU)中。

一般来说,修复查询内并行性死锁的两种方法:

  • 避免并行性(通过调整查询,以便它不走的同时,使用MAXDOP提示等) -这是包括在其他答案托马斯Costers
  • 将最新的服务包/累积更新应用到 SQL Server