【发布时间】:2020-09-17 13:59:49
【问题描述】:
我们在开发过程中遇到了一个奇怪的问题,正在寻找有关临时表上 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 并锁定临时表,从而导致死锁。当我们使用提示 OPTION MAXDOP(1) 即强制单线程查询时,不会出现死锁。同样,如果我们先创建临时表,然后再创建一个 INSERT 也可以。
我们有两个可行的解决方案来解决这个问题,但我仍然不清楚为什么会出现问题。我想我的问题是:
1/ SELECT INTO 导致临时表自死锁的真正原因是什么?
2/为什么错误只发生在事务的上下文中?
3/ 为什么死锁只发生在SELECT INTO 而不是常规INSERT?
谢谢大家!
编辑:下面的死锁图
【问题讨论】:
-
你能发布一个死锁图吗?
-
什么版本的 SQL Server?我昨天第一次遇到了这个确切的问题。这可能是相关的:feedback.azure.com/forums/908035-sql-server/suggestions/…
-
@MartinSmith,我编辑了上面的帖子
-
@MattG 我们正在使用 SQL Azure(专门托管的实例)
-
我对此有所了解,但无法重现该问题。这里需要进行哪些更改才能重现? dbfiddle.uk/…
标签: json sql-server temp-tables sqlperformance database-deadlocks