通过在 sql 服务器中禁用 ALLOW_PAGE_LOCKS 来避免死锁
avoiding deadlock by disabling ALLOW_PAGE_LOCKS in sql server
我有一个 grails 应用程序,它公开了一个 api,它在下面有点重 DML。所有 DML 都是通过 GORM 发生的,我没有直接使用 Sql。当这个 api 同时被命中时,我 运行 经常陷入死锁,而且几乎总是主键上的这个键锁总是死锁日志的一部分。这是来自 sql 服务器的日志片段:
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" 依此类推到其他一些 table。
Table 进化触发定义如下:
ALTER TRIGGER [dbo].[tr_del_Evolutions] ON [dbo].[进化]
删除
作为
从 EvolutionRuns 中删除
来自 EvolutionRuns
INNER JOIN 删除于 deleted.evolutionId=evolutionRuns.evolutionId
table ParticipantTrace 的约束定义为:
ALTER TABLE [dbo].[ParticipantTrace] WITH CHECK ADD CONSTRAINT [FK_ParticipantTrace_EvolutionRuns] FOREIGN KEY([evolutionRunId])
参考资料 [dbo].[EvolutionRuns] ([evolutionRunId])
删除级联
table Critters 的约束定义为:
ALTER TABLE [dbo].[Critters] WITH CHECK ADD CONSTRAINT [FK_Critters_EvolutionRuns] 外键([evolutionRunId])
参考资料 [dbo].[EvolutionRuns] ([evolutionRunId])
删除级联
- 我已经在引用键上添加了索引,但这对
全部。
- 我尝试在 grails 服务中切换事务,但也无济于事。我已经正确设置了具有正确 belongsTo/hasMany 关系的域,但是由于删除是通过级联删除发生的,所以不确定 GORM 是否与它有任何关系!
我发现禁用 ALLOW_PAGE_LOCKS 为我解决了死锁问题,但大多数博客建议不要这样做,而是适当地添加索引。
我能解决这个键锁 + 死锁问题吗?
非常感谢您的建议,谢谢。
是的,由于级联删除,您遇到了死锁。
这是您的图表:
victim=process59494c8
has RangeS-U on PK_ParticipantTrace
waits for
RangeS-U on PK_Critters
winner =process4a1fb88
has RangeX-X on keylock PK_Critters
(EPM-DEV.dbo.Critters)
waits for RangeS-U on keylock
PK_ParticipantTrace (EPM-DEV.dbo.ParticipantTrace)
2 个进程以相反的顺序访问这 2 tables,所以一个等待第二个 table 的锁,在第一个上持有锁,另一个在持有第一个时等待锁锁定第二个。
两个进程都认为只从 1 table 中删除,而是以不同的顺序从两者中删除
我有一个 grails 应用程序,它公开了一个 api,它在下面有点重 DML。所有 DML 都是通过 GORM 发生的,我没有直接使用 Sql。当这个 api 同时被命中时,我 运行 经常陷入死锁,而且几乎总是主键上的这个键锁总是死锁日志的一部分。这是来自 sql 服务器的日志片段:
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" 依此类推到其他一些 table。
Table 进化触发定义如下:
ALTER TRIGGER [dbo].[tr_del_Evolutions] ON [dbo].[进化] 删除 作为 从 EvolutionRuns 中删除 来自 EvolutionRuns INNER JOIN 删除于 deleted.evolutionId=evolutionRuns.evolutionId
table ParticipantTrace 的约束定义为:
ALTER TABLE [dbo].[ParticipantTrace] WITH CHECK ADD CONSTRAINT [FK_ParticipantTrace_EvolutionRuns] FOREIGN KEY([evolutionRunId]) 参考资料 [dbo].[EvolutionRuns] ([evolutionRunId]) 删除级联
table Critters 的约束定义为:
ALTER TABLE [dbo].[Critters] WITH CHECK ADD CONSTRAINT [FK_Critters_EvolutionRuns] 外键([evolutionRunId]) 参考资料 [dbo].[EvolutionRuns] ([evolutionRunId]) 删除级联
- 我已经在引用键上添加了索引,但这对 全部。
- 我尝试在 grails 服务中切换事务,但也无济于事。我已经正确设置了具有正确 belongsTo/hasMany 关系的域,但是由于删除是通过级联删除发生的,所以不确定 GORM 是否与它有任何关系!
我发现禁用 ALLOW_PAGE_LOCKS 为我解决了死锁问题,但大多数博客建议不要这样做,而是适当地添加索引。
我能解决这个键锁 + 死锁问题吗?
非常感谢您的建议,谢谢。
是的,由于级联删除,您遇到了死锁。 这是您的图表:
victim=process59494c8
has RangeS-U on PK_ParticipantTrace
waits for RangeS-U on PK_Critters
winner =process4a1fb88
has RangeX-X on keylock PK_Critters (EPM-DEV.dbo.Critters)
waits for RangeS-U on keylock PK_ParticipantTrace (EPM-DEV.dbo.ParticipantTrace)
2 个进程以相反的顺序访问这 2 tables,所以一个等待第二个 table 的锁,在第一个上持有锁,另一个在持有第一个时等待锁锁定第二个。 两个进程都认为只从 1 table 中删除,而是以不同的顺序从两者中删除