微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用OPENJSON中的临时表在SELECT INTO上进行SQL Server自死锁

如何解决使用OPENJSON中的临时表在SELECT INTO上进行SQL Server自死锁

我们在开发中遇到了一个奇怪的问题,正在寻找有关临时表上带有SELECT INTO的自锁问题的解释。

我们有一个例程,可以将一些相当复杂的JSON文档转换为表格形式。目前,我们正在使用OPEnjsON来完成此操作,通常效果很好。

此转换发生在触发器的上下文中。当将一个或多个行插入表中时,将生成一组JSON文档,将其存储在单个变量中,并传递给以下例程。看起来像这样:

SELECT 
a.[ID],b.[Some stuff here...]
INTO #MyTempTable
FROM OPEnjsON(@MyJSONDocuments)
WITH (
    ID VARCHAR(40),nestedDocument NVARCHAR(MAX) AS JSON) a
CROSS APPLY OPEnjsON(nestedDocument,'$') b

当我们在SSMS中运行它时,它就可以正常工作。临时表已生成并填充,没有问题。当我们将其移至触发器并仅在基础表中插入一行(即@MyJSONDocuments是单个文档的数组)时,它也可以正常工作。当我们插入两行或更多行,并且@MyJSONDocuments在数组中包含多个文档时,我们会感到恐惧:

Transaction (Process ID x) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

当在SSMS中将SELECT INTO语句包装到BEGIN TRAN / COMMIT TRAN中时,也会遇到相同的死锁错误

经过一些研究,我们发现问题可能是来自多个线程的并发问题,这些线程正在解析JSON并同时锁定temp表,从而导致死锁。当我们使用提示OPTION MAXDOP(1)时,即强制查询是单线程的,没有死锁。同样,如果我们先创建临时表,然后再创建一个INSERT,它也会起作用。

对于这个问题,我们有两个可行的解决方案,但是我仍然不清楚为什么这是一个问题。我想我的问题是:

1 / SELECT INTO导致临时表上的自死锁的真正原因是什么?

2 /为什么错误仅在交易中发生?

3 /为什么死锁只发生在SELECT INTO而不是常规INSERT上?

谢谢大家!

编辑:下面的死锁图

enter image description here

解决方法

不确定该问题的完整答案,但我认为该问题与在事务上下文中并行访问OPENJSON结果有关。我遇到了完全相同的问题,可以通过设置OPTION(MAXDOP 1)在查询的那一部分上强制执行串行计划来解决。

尝试一下:

Object.create

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。