删除语句死锁


11

运行SQL Server作业时出现死锁。死锁发生在简单的DELETE语句上。我本以为必须要运行SELECT / UPDATE查询才能引起死锁?但是看起来是DELETE / DELETE死锁...

我要寻找的是为什么会出现DELETE / DELETE死锁。(据我所知)传递了不同的参数。

有任何想法吗?谢谢。

deadlock-list
2014-05-20 07:30:09.66 spid25s      deadlock victim=process409048
2014-05-20 07:30:09.66 spid25s       process-list
2014-05-20 07:30:09.66 spid25s        process id=process409048 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127294 waittime=4352 ownerId=629860973 transactionname=DELETE lasttranstarted=2014-05-20T07:30:05.307 XDES=0x397219620 lockMode=U schedulerid=5 kpid=3792 status=suspended spid=150 sbid=0 ecid=3 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:05.307 lastbatchcompleted=2014-05-20T07:30:05.307 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629860973 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
2014-05-20 07:30:09.66 spid25s     DELETE FROM dbo.UserDetailsData WHERE        (Username = @P1) AND (UserDate = @P2)     
2014-05-20 07:30:09.66 spid25s          frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
2014-05-20 07:30:09.66 spid25s     unknown     
2014-05-20 07:30:09.66 spid25s         inputbuf
2014-05-20 07:30:09.66 spid25s        process id=process432e08 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127916 waittime=2648 ownerId=629859744 transactionname=DELETE lasttranstarted=2014-05-20T07:30:04.833 XDES=0x4c3426b50 lockMode=U schedulerid=6 kpid=5988 status=suspended spid=146 sbid=0 ecid=3 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:04.833 lastbatchcompleted=2014-05-20T07:30:04.820 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629859744 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
2014-05-20 07:30:09.66 spid25s     DELETE FROM dbo.UserDetailsData WHERE        (Username = @P1) AND (UserDate = @P2)     
2014-05-20 07:30:09.66 spid25s          frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
2014-05-20 07:30:09.66 spid25s     unknown     
2014-05-20 07:30:09.66 spid25s         inputbuf
2014-05-20 07:30:09.66 spid25s        process id=process39ea562c8 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127916 waittime=4352 ownerId=629860973 transactionname=DELETE lasttranstarted=2014-05-20T07:30:05.307 XDES=0x13e0e4b50 lockMode=U schedulerid=2 kpid=7124 status=suspended spid=150 sbid=0 ecid=1 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:05.307 lastbatchcompleted=2014-05-20T07:30:05.307 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629860973 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2

5
不,在SELECT / UPDATE之外的其他情况下,可能会发生死锁。您真正需要的只是两个流程,每个流程都需要对方持有的资源。(1)DELETE语句是较大事务的一部分吗?(2)您可以将死锁XML张贴在某个地方,而不是糟糕的错误日志文本吗?
亚伦·伯特兰

您能否发布dbo.UserDetailsData包含所有索引的表架构?另外,您知道这些语句是否使用相同的参数调用吗?鉴于两者都使用了零日志,我想知道您是否需要做的就是序列化调用,因为它们之间会相互踩踏。
乔恩·塞格尔

如何获取XML?从SQL Server错误日志中获取了错误。用不同的参数调用语句。最近,我们添加了一些在UserDate字段上进行过滤的过滤索引。
2014年

在事件探查器中捕获死锁图事件。然后,在捕获它之后,右键单击该行->提取事件数据->将其另存为.xdl,然后将其内容(它是xml)发布到Pastebin(或类似位置)上。
玛丽安

1
嗨,XML发布在这里...希望能有所帮助! dl.dropboxusercontent.com/u/16953128/DeadlockTest.xdl
K09

Answers:


14

我要寻找的是为什么会出现DELETE / DELETE死锁。

出现死锁的原因是:

  1. spid 54 ecid 0获取更新(U)页面锁定PAGE: 12:1:5147422
  2. spid 166 ecid 3请求U在同一页面上进行更新()页面锁定,并被阻止
  3. spid 54 ecid 2请求U在同一页面上进行更新()页面锁定...

正在为查询预取页面,并通过获取了更新锁ecid 0。那是上面的步骤1。在第3步中,相同并行查询(ecid 2)的子线程请求相同的锁。通常,这不会有问题。SQL Server知道ecid 0并且ecid 2是同一父进程的线程。不幸的是,步骤2阻碍了这一步,并导致了死锁。

就是说,您不应该真正在意死锁的原因,重要的问题是如何避免死锁。答案是为.NET提供有效的访问路径DELETE。该语句需要查找row WHERE Username = @P1 AND UserDate = @P2,因此您应该在这些列上键入索引。

当然,您确实有这样的索引。在真正的问题是,为什么你的问题开始您添加过滤索引后发生。

答案是需要额外的列信息才能找到过滤后的索引行以删除(并检查其谓词)。如果查询使用一个窄/每行执行计划,则执行引擎将无法像在一个宽/每索引计划中那样在“聚集索引删除”运算符中获取额外的列。

您可以在此博客文章中找到有关此内容的更多详细信息以及一个有效的示例。

在这种情况下,列信息需要来自计划部分的“聚簇索引删除”右侧,因此使用了并行聚簇索引扫描,您将获得一个具有高死锁可能性的慢查询。

答案是执行以下操作之一:

  1. 删除过滤的索引
  2. 将过滤后的索引键/包含/谓词列添加到现有名称/日期索引
  3. 强制执行广泛的更新计划(不支持这样做的方法)
  4. 在快照隔离(不是RCSI)下运行查询

选项2是我的强烈偏好。

选项4(感谢Jack Douglas)具有消除死锁的优势,鉴于更改的不相干性质,它不应引起任何“更新冲突”,但是它确实需要在数据库级别启用快照隔离,显式更改隔离级别,并且不会解决潜在的问题:您仍然会浪费大量的并行表扫描,而真正想要的是一个不错的索引查找。

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.