Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何在从联接表中选择时避免死锁?_Sql Server - Fatal编程技术网

Sql server 如何在从联接表中选择时避免死锁?

Sql server 如何在从联接表中选择时避免死锁?,sql-server,Sql Server,我有两个非常简单的表,我们称它们为[UserData1]和[UserData2]。它们都有[UserId]列作为主键。我正在对这两个表运行两种类型的查询。一种是SELECT语句,返回特定用户的组合数据: SELECT <a subset of columns from both tables> FROM [UserData1] ud1 FULL OUTER JOIN [UserData2] ud2 ON ud1.[UserId] = ud2.[UserId] WHERE

我有两个非常简单的表,我们称它们为[UserData1]和[UserData2]。它们都有[UserId]列作为主键。我正在对这两个表运行两种类型的查询。一种是SELECT语句,返回特定用户的组合数据:

SELECT <a subset of columns from both tables>
FROM [UserData1] ud1
    FULL OUTER JOIN [UserData2] ud2 ON ud1.[UserId] = ud2.[UserId]
WHERE
    ud1.[UserId] = @UserId OR ud2.[UserId] = @UserId
BEGIN TRANSACTION

UPDATE [UserData1]
SET <new values>
WHERE [UserId] = @UserId

UPDATE [UserData2]
SET <new values>
WHERE [UserId] = @UserId

COMMIT TRANSACTION
显然,运行SELECT语句的进程在[UserData1]之前获得了[UserData2]表上的锁,尽管有强制顺序提示。

第一件事(我认为)是第一个查询中的where子句是多余的。在连接中有相同的东西,在连接中更好,因为您正在进行完全的外部连接

在避免死锁方面,它可能与如何处理第一个查询有关,即删除读锁。如果应用程序只是读取数据,而这不是用户事务的一部分,那么一旦读取完成,第二个查询将能够完成,并且不会出现死锁


您的环境中是否遇到了死锁,或者只是猜测您将遇到死锁。如果您正在发布死锁图,那么我们可以看到实际的锁是什么

使用
READ COMMITTED
时,select不应参与死锁,因为它一次只能获取一个锁。读取锁定行后,可以立即释放锁


我强烈建议您启用快照隔离。它将解决这个问题。熟悉涉及的3种开销:增加的行大小、tempdb写入和微小的读取开销。大多数时候,它们没有意义。

是的,我遇到了僵局。我用死锁跟踪更新了问题。运行SELECT query的进程似乎在尝试获取[UserData1]上的另一个锁时保留了第一个锁([UserData2]),而不是丢弃第一个锁。同意快照隔离将解决此问题,并且开销可能可以忽略不计。我只是好奇这是否可以通过其他方式解决。例如,是否可以将其排列为一次锁定一个联接表?从死锁跟踪(添加到问题正文)可以看出,当SELECT尝试锁定另一个表时,一个表([UserData2])上的锁似乎没有被释放。X锁永远不会被释放,因此回滚可以保证工作。我更困惑的是,为什么select会同时占用多个锁?SQL Server通常锁定行,而不是表。您应该调试这个。select事务中是否有其他查询?添加
设置事务隔离级别READ COMMITTED
。您可以通过
TABLOCKX
”在更新中修改表来解决这个问题,但这对并发性来说是可怕的。也许您还需要在select查询中以相同的顺序对它们进行X锁定。
   Deadlock encountered .... Printing deadlock information
   Wait-for graph

   Node:1
   KEY: 17:72057594039173120 (e21762ccf3dc) CleanCnt:3 Mode:X Flags: 0x1
    Grant List 1:
      Owner:0x00000020F75B0480 Mode: X        Flg:0x40 Ref:0 Life:02000000 SPID:72 ECID:0 XactLockInfo: 0x00000020EB13ED68
      SPID: 72 ECID: 0 Statement Type: UPDATE Line #: 1
      Input Buf: Language Event: (@UserId bigint,@DataColumn2 int)update
   Requested by: 
     ResType:LockOwner Stype:'OR'Xdes:0x00000020FC98DA40 Mode: S SPID:75 BatchID:0 ECID:0 TaskProxy:(0x00000020DAB38608) Value:0xf75abbc0 Cost:(0/0)

   Node:2
   KEY: 17:72057594039107584 (e21762ccf3dc) CleanCnt:9 Mode:S Flags: 0x1
    Grant List 1:
      Owner:0x00000020EEBFE580 Mode: S        Flg:0x40 Ref:1 Life:00000000 SPID:75 ECID:0 XactLockInfo: 0x00000020FC98DA80
      SPID: 75 ECID: 0 Statement Type: SELECT Line #: 1
      Input Buf: Language Event: (@UserId bigint)select [t].[UserId], t.[DataColumn2], t1.[DataColumn1]
   Requested by: 
     ResType:LockOwner Stype:'OR'Xdes:0x00000020EB13ED28 Mode: X SPID:72 BatchID:0 ECID:0 TaskProxy:(0x0000001F671C6608) Value:0xf75b5400 Cost:(0/456)

   Victim Resource Owner:
    ResType:LockOwner Stype:'OR'Xdes:0x00000020FC98DA40 Mode: S SPID:75 BatchID:0 ECID:0 TaskProxy:(0x00000020DAB38608) Value:0xf75abbc0 Cost:(0/0)
  deadlock-list
   deadlock victim=process20fda2ccf8
    process-list
     process id=process20fda2ccf8 taskpriority=0 logused=0 waitresource=KEY: 17:72057594039173120 (e21762ccf3dc) waittime=4526 ownerId=3416711 transactionname=SELECT lasttranstarted=2013-07-11T18:42:20.943 XDES=0x20fc98da40 lockMode=S schedulerid=20 kpid=2800 status=suspended spid=75 sbid=0 ecid=0 priority=0 trancount=0 lastbatchstarted=2013-07-11T18:42:20.950 lastbatchcompleted=2013-07-11T18:42:20.950 lastattention=1900-01-01T00:00:00.950 clientapp=.Net SqlClient Data Provider hostname=hostname hostpid=27716 loginname=loginname isolationlevel=read committed (2) xactid=3416711 currentdb=17 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
      executionStack
       frame procname=adhoc line=1 stmtstart=36 sqlhandle=0x020000001fcbbe1423a0c65cc8411344c6040e879195af3a0000000000000000000000000000000000000000
  select [t].[UserId], t.[DataColumn2], t1.[DataColumn1] from [UserData1] t1 full outer join [UserData2] t on t1.[UserId]=t.[UserId] where t.[UserId]=@UserId or t1.[UserId]=@UserId option (force order)     
       frame procname=unknown line=1 sqlhandle=0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
  unknown     
      inputbuf
  (@UserId bigint)select [t].[UserId], t.[DataColumn2], t1.[DataColumn1] from [UserData1] t1 full outer join [UserData2] t on t1.[UserId]=t.[UserId] where t.[UserId]=@UserId or t1.[UserId]=@UserId option (force order)    
     process id=process20fd055498 taskpriority=0 logused=456 waitresource=KEY: 17:72057594039107584 (e21762ccf3dc) waittime=4525 ownerId=3416764 transactionname=user_transaction lasttranstarted=2013-07-11T18:42:20.960 XDES=0x20eb13ed28 lockMode=X schedulerid=9 kpid=6024 status=suspended spid=72 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2013-07-11T18:42:20.970 lastbatchcompleted=2013-07-11T18:42:20.970 lastattention=1900-01-01T00:00:00.970 clientapp=.Net SqlClient Data Provider hostname=hostname hostpid=27716 loginname=loginname isolationlevel=read committed (2) xactid=3416764 currentdb=17 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
      executionStack
       frame procname=adhoc line=1 stmtstart=508 sqlhandle=0x02000000c0d74a32597ec460559a2d5dbdc92f7746cdce270000000000000000000000000000000000000000
  update UserData2 set [LastModified]=getutcdate(), [DataColumn2]=[DataColumn2]+@DataColumn2Increment where [UserId]=@UserId     
       frame procname=unknown line=1 sqlhandle=0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
  unknown     
      inputbuf
  (@UserId bigint,@DataColumn2Increment int)update UserData2 set [LastModified]=getutcdate(), [DataColumn2]=[DataColumn2]+@DataColumn2Increment where [UserId]=@UserId    
    resource-list
     keylock hobtid=72057594039173120 dbid=17 objectname=database_name.dbo.UserData1 indexname=1 id=lock20ec75b380 mode=X associatedObjectId=72057594039173120
      owner-list
       owner id=process20fd055498 mode=X
      waiter-list
       waiter id=process20fda2ccf8 mode=S requestType=wait
     keylock hobtid=72057594039107584 dbid=17 objectname=database_name.dbo.UserData2 indexname=1 id=lock20ec07f600 mode=S associatedObjectId=72057594039107584
      owner-list
       owner id=process20fda2ccf8 mode=S
      waiter-list
       waiter id=process20fd055498 mode=X requestType=wait