【问题标题】:SQL Server Self Deadlock on SELECT INTO with temp table from OPENJSONSQL Server Self Deadlock on SELECT INTO with temp table from OPENJSON
【发布时间】: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


【解决方案1】:

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

试试这个:

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
OPTION (MAXDOP 1)

【讨论】:

  • 我同意这解决了问题(这是我现在使用的,而不是单独创建临时表然后插入其中。)我也认为只有当我有CROSS APPLY这也会发生。我想我只是在寻找发生这种情况的技术原因,以及是否涉及交易的重要性。
  • 我同意,这解决了问题,但我们不必逐个查询,而是通过使用以下方法调整并行度以使其与内核数保持一致:EXEC sp_configure 'show advanced options', 1 ;去重新配置覆盖; GO EXEC sp_configure '最大并行度', 4;去重新配置覆盖;去
猜你喜欢
  • 2021-11-17
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
  • 2022-08-02
  • 1970-01-01
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多