通过在 sql server 中禁用 ALLOW_PAGE_LOCKS 来避免死锁

问题描述 投票:0回答:1

我有一个 grails 应用程序,它公开了一个底层有大量 DML 的 api。所有 DML 都是通过 GORM 进行的,我没有直接使用 Sql。当同时访问此 api 时,我会非常频繁地遇到死锁,并且几乎总是主键上的键锁始终是死锁日志的一部分。这是来自 sql server 的日志片段:


Date,Source,Severity,Message
09/13/2017 17:02:13,spid21s,Unknown,waiter id=process4a1fb88 mode=RangeS-U requestType=wait
09/13/2017 17:02:13,spid21s,Unknown,waiter-list
09/13/2017 17:02:13,spid21s,Unknown,owner id=process59494c8 mode=RangeS-U
09/13/2017 17:02:13,spid21s,Unknown,owner-list
09/13/2017 17:02:13,spid21s,Unknown,keylock hobtid=72057594142588928 dbid=17 objectname=EPM-DEV.dbo.ParticipantTrace indexname=PK_ParticipantTrace id=lock8d0c6c80 mode=RangeS-U associatedObjectId=72057594142588928
09/13/2017 17:02:13,spid21s,Unknown,waiter id=process59494c8 mode=RangeS-U requestType=wait
09/13/2017 17:02:13,spid21s,Unknown,waiter-list
09/13/2017 17:02:13,spid21s,Unknown,owner id=process4a1fb88 mode=RangeX-X
09/13/2017 17:02:13,spid21s,Unknown,owner-list
09/13/2017 17:02:13,spid21s,Unknown,keylock hobtid=72057594142523392 dbid=17 objectname=EPM-DEV.dbo.Critters indexname=PK_Critters id=lock909d8a00 mode=RangeX-X associatedObjectId=72057594142523392
09/13/2017 17:02:13,spid21s,Unknown,resource-list
09/13/2017 17:02:13,spid21s,Unknown,(@P0 bigint)DELETE FROM evolutions WHERE evolutionId=@P0
09/13/2017 17:02:13,spid21s,Unknown,inputbuf
09/13/2017 17:02:13,spid21s,Unknown,unknown
09/13/2017 17:02:13,spid21s,Unknown,frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
09/13/2017 17:02:13,spid21s,Unknown,DELETE FROM evolutions WHERE evolutionId=@P0
09/13/2017 17:02:13,spid21s,Unknown,frame procname=adhoc line=1 stmtstart=24 sqlhandle=0x02000000791d7d1fc5ed65e7287c3344e4d309e75a370674
09/13/2017 17:02:13,spid21s,Unknown,INNER JOIN deleted ON deleted.evolutionId=evolutionRuns.evolutionId
09/13/2017 17:02:13,spid21s,Unknown,FROM EvolutionRuns
09/13/2017 17:02:13,spid21s,Unknown,DELETE FROM EvolutionRuns
09/13/2017 17:02:13,spid21s,Unknown,frame procname=EPM-DEV.dbo.tr_del_Evolutions line=7 stmtstart=314 sqlhandle=0x030011005729580f72961b01ada700000000000000000000
09/13/2017 17:02:13,spid21s,Unknown,executionStack
09/13/2017 17:02:13,spid21s,Unknown,process id=process4a1fb88 taskpriority=0 logused=278800 waitresource=KEY: 17:72057594142588928 (ffffffffffff) waittime=9495 ownerId=18259173 transactionname=implicit_transaction lasttranstarted=2017-09-13T17:02:03.317 XDES=0xe5b7d970 lockMode=RangeS-U schedulerid=1 kpid=3088 status=suspended spid=222 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2017-09-13T17:02:03.580 lastbatchcompleted=2017-09-13T17:02:03.580 clientapp=PlatformService hostname=dshrestha hostpid=0 loginname=affiservUser isolationlevel=read committed (2) xactid=18259173 currentdb=17 lockTimeout=4294967295 clientoption1=671219744 clientoption2=128058
09/13/2017 17:02:13,spid21s,Unknown,(@P0 bigint)DELETE FROM evolutionRuns WHERE evolutionId=@P0
09/13/2017 17:02:13,spid21s,Unknown,inputbuf
09/13/2017 17:02:13,spid21s,Unknown,unknown
09/13/2017 17:02:13,spid21s,Unknown,frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
09/13/2017 17:02:13,spid21s,Unknown,DELETE FROM evolutionRuns WHERE evolutionId=@P0
09/13/2017 17:02:13,spid21s,Unknown,frame procname=adhoc line=1 stmtstart=24 sqlhandle=0x02000000c256370374cd8f1b213e95ec8d6768101b5b0230
09/13/2017 17:02:13,spid21s,Unknown,executionStack
09/13/2017 17:02:13,spid21s,Unknown,process id=process59494c8 taskpriority=0 logused=16832 waitresource=KEY: 17:72057594142523392 (ab422a83b86b) waittime=9503 ownerId=18259172 transactionname=implicit_transaction lasttranstarted=2017-09-13T17:02:03.317 XDES=0xe5773970 lockMode=RangeS-U schedulerid=2 kpid=8652 status=suspended spid=178 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2017-09-13T17:02:03.363 lastbatchcompleted=2017-09-13T17:02:03.357 clientapp=PlatformService hostname=dshrestha hostpid=0 loginname=affiservUser isolationlevel=read committed (2) xactid=18259172 currentdb=17 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128058
09/13/2017 17:02:13,spid21s,Unknown,process-list
09/13/2017 17:02:13,spid21s,Unknown,deadlock victim=process59494c8
09/13/2017 17:02:13,spid21s,Unknown,deadlock-list

由于触发器以及级联删除,从“evolution”中删除会将删除传播到“evolutionRuns”等其他一些表。

表演化定义了触发器,如下所示:

更改触发器 [dbo].[tr_del_Evolutions] ON [dbo].[Evolutions] 用于删除 作为 从 EvolutionRun 中删除 来自进化运行 INNER JOIN 已删除 ON displayed.evolutionId=evolutionRuns.evolutionId

表 ParticipantTrace 的约束定义为:

更改表 [dbo].[ParticipantTrace] 带检查添加约束 [FK_ParticipantTrace_EvolutionRuns] 外键 ([evolutionRunId]) 参考文献 [dbo].[EvolutionRuns] ([evolutionRunId]) 删除级联

table Critters 的约束定义为:

更改表 [dbo].[Critters] 带检查添加约束 [FK_Critters_EvolutionRuns] 外键 ([evolutionRunId]) 参考文献 [dbo].[EvolutionRuns] ([evolutionRunId]) 删除级联

  • 我在引用键上添加了索引,但这没有帮助 全部。
  • 我尝试在 grails 服务中切换事务,但这也没有帮助。我已经正确设置了域并具有正确的 ownTo/hasMany 关系,但由于删除是通过级联删除进行的,不确定 GORM 与它有什么关系!

我发现禁用 ALLOW_PAGE_LOCKS 可以解决我的死锁问题,但大多数博客建议不要这样做,而是正确添加索引。

有什么办法可以解决这个键锁+死锁问题吗?

非常感谢您的建议,谢谢。

sql-server grails grails-orm
1个回答
2
投票

是的,由于级联删除,您遇到了死锁。 这是您的图表:

受害者=process59494c8

PK_ParticipantTrace 上有 RangeS-U

等待 PK_Critters 上的 RangeS-U

获胜者=process4a1fb88

钥匙锁 PK_Critters 上有 RangeX-X (EPM-DEV.dbo.Critters)

等待 RangeS-U 开启钥匙锁 PK_ParticipantTrace (EPM-DEV.dbo.ParticipantTrace)

2 进程以相反的顺序访问这两个表,因此一个进程在持有第一个表上的锁的情况下等待第二个表上的锁,而另一个进程则在持有第二个表上的锁的同时等待第一个表上的锁。 两个进程都认为只从 1 个表中删除,但却以不同的顺序从两个表中删除

© www.soinside.com 2019 - 2024. All rights reserved.