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


10

我在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

错误信息:

事务(进程ID 56)与另一个进程在通用的可等待对象资源上处于死锁状态,并且被选择为死锁牺牲品。重新运行事务。

线索:

  • 如果查询使用CCI以外的其他索引,则不会死锁。
  • 如果删除三个tenantid过滤器中的两个,则不会死锁。
  • 如果我选择前32位或更低,则不会死锁。
  • 如果添加OPTION(MAXDOP 1),则不会死锁。
  • 我可以在混乱的PROD副本,PROD只读次要副本和PROD本身中对此进行复制。
  • 我无法在DEV或INT中复制此行为。
  • 如果我将WITH(NOLOCK)添加到所有3个表联接中,它仍然会死锁
  • 查询自身会死锁。当没有其他活动进程时,它将死锁。
  • 没有并行性的查询计划不会死锁

死锁XML在这里

我们的PROD版本:

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

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

Answers:


8

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

FIX:当您在SQL Server 2016和2017中的群集的列存储索引上运行并行查询时,会发生死锁

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

它作为SP1 CU7的一部分发布。如果您没有达到该CU,则应该尝试一下。此修复程序也将包含在SP2中(任何CU)。

通常,用于修复查询内并行性死锁的两种方法:

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

2

您是否检查了以下有关Intra-Query并行线程死锁的博客

SyncPoint如果我没有记错的话,该资源指示使用交换事件。
查看死锁的参与者,您会发现它们都来自相同的spid(55)和batch(0),但使用的线程不同。这表明它们都是同一并行查询的一部分,并且通过使用来运行查询时您不会收到任何死锁这一事实得到了证实MAXDOP 1。对于查询内并行线程死锁,单个查询的线程最终将彼此死锁,等待同步对象(在您的情况下为SyncPoints)。

上一次,当我目睹这种行为时,我能够进一步优化查询,从而防止查询使用并行执行计划。我怀疑您通过将结果集限制为32条记录或使用了不同的索引来做同样的事情。
另一个选择是将其添加MAXDOP 1到您的查询中,尽管不是该选项的忠实支持者。

但是在摆弄这两个选项之前,请先检查您是否在最新的SP / CU上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.