我有两个非常简单的表,让我们称它们为[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
Run Code Online (Sandbox Code Playgroud)
另一个是为特定用户更新两个表中的用户数据的事务:
BEGIN TRANSACTION
UPDATE [UserData1]
SET <new values>
WHERE [UserId] = @UserId
UPDATE [UserData2]
SET <new values>
WHERE [UserId] = @UserId
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)
这里的问题是SELECT语句中获取共享表锁的顺序是不确定的,如果SQL Server决定在[UserData1]之前锁定[UserData2],这可能(并且实际上)会导致传统的死锁情况.在这种情况下,避免死锁的最佳方法是什么?
将这些表合并到一个表中,对吗?我希望这很容易.假设有理由将它们分开.
READ UNCOMMITTED/NOLOCK提示?假设不能容忍脏读.
SNAPSHOT隔离级别?这样可以解决问题,但我不确定所涉及的开销.
所以问题归结为:有没有办法保证获取连接表的锁定顺序?
起初我认为这可以通过FORCE ORDER查询提示来实现,但后来我通过实验发现它不一定强制执行表被锁定的顺序.在这种特殊情况下的另一个解决方案是为每个表发出单独的SELECT查询,然后在应用程序层中组合两个单行记录集,但是如果我需要为多个用户进行查询,我仍然希望得到所有导致一个记录集.
更新:
这是死锁跟踪的摘录:
Deadlock encountered .... Printing deadlock information
Wait-for graph
Node:1
KEY: 17:72057594039173120 (e21762ccf3dc) CleanCnt:3 Mode:X …Run Code Online (Sandbox Code Playgroud) sql-server ×1