chr*_*may 6 foreign-key sql-server deadlock locking
我正在处理一个死锁问题。
进程 A 正在对 TableA 执行简单的 INSERT,它对 TableB 有一个 FK
进程 B 正在对包含 TableA 和 TableB 的连接执行复杂的 SELECT
我将在下面包含跟踪信息,但基本上我认为正在发生的是由于 TableA 对 TableB 具有 FK,因此对 TableA 的插入导致了 TableB 的 Primany INDEX 上的排他锁 (X)。我们确实为那个 FK 启用了参照完整性,但是不需要通过插入到 TableA 来更新 TableB,所以我觉得奇怪的是,只需要一个排他锁来检查 FK 值的存在。
这是预期的行为吗?如果是这样,我可以做些什么来减轻这种情况?老实说,我没想到这样一个基本/香草插入会导致僵局。
此外,这不是我真正的问题,但如果您碰巧知道“子资源=满”意味着什么,我会很想知道。
编辑:只是要清楚僵局:
processInserting 正在插入到 TableA 并且在 TableB 上的主索引(TableA 的外键)上有一个 X 锁。ProcessSelecting 正在等待对该索引的 RangeS-S 锁定。
processSelecting 从包括 TableA 和 TableB 在内的许多表的连接中进行选择,并且在 TableA 上有一个 S 锁(因为它正在连接它)。ProcessInserting 正在等待此表上的 IX 锁。
编辑 2:提供更多细节。我正在调用 processSelecting 的“选择”查询是一个非常折磨人的查询,它使用一个折磨人的视图作为连接的一部分,所以看起来有点混乱。
这是 RoutePlan (TableA) 和 Form (TableB) 表的 DDL。
RoutePlan 有一个触发器来记录历史变化:
执行 INSERT 到 Routeplan 的 SP 是:
执行 SELECT 的 SP 是:
而 View CurrentAndPriorApprovers_View 被定义为
这是完整的跟踪日志信息
resource-list
keylock hobtid=72057594059882496 dbid=66 objectname=TableB indexname=PK_TableB id=lock204d08500 mode=X associatedObjectId=72057594059882496
owner-list
owner id=processInserting mode=X
waiter-list
waiter id=processSelecting mode=RangeS-S requestType=wait
objectlock lockPartition=0 objid=516196889 subresource=FULL dbid=66 objectname=TableA id=lock2044c5080 mode=S associatedObjectId=516196889
owner-list
owner id=processSelecting mode=S
waiter-list
waiter id=processInserting mode=IX requestType=convert
Run Code Online (Sandbox Code Playgroud)
这是我消除死锁的第一个建议(这是一个非常常见的原因,每次都具有相同的分辨率)。您的RoutePlan_Save程序目前具有以下逻辑:
IF EXISTS (SELECT ... WHERE key = @key)
UPDATE ... WHERE key = @key;
ELSE
INSERT(key) VALUES(@key);
Run Code Online (Sandbox Code Playgroud)
因此,您实际上有两个查询需要锁定表,无论您最终是要执行插入还是更新。别那样做!检查一行是否存在,然后在单独的查询中触发更新语句,再次检查该行是否存在有什么意义?这需要更多的资源,而不是更少,而不仅仅是尝试更新不知道它是否存在的行。所以改为这样做:
BEGIN TRANSACTION;
UPDATE ... WHERE key = @key;
IF @@ROWCOUNT = 0
BEGIN
INSERT(key) VALUES(@key);
END
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)
您还可以使用不同的隔离级别来隔离其他只读进程,该级别不需要它们等待写入操作完成。NOLOCK / READ UNCOMMITTED是一个流行的,但是READ COMMITTED SNAPSHOT- 假设你可以在 tempdb 上受到打击 - 恕我直言更好。还有其他选择。昨天我碰巧写了一篇关于这个的博客:
| 归档时间: |
|
| 查看次数: |
2495 次 |
| 最近记录: |