读者编写器在SQL Server中死锁

时间:2014-12-26 13:31:54

标签: sql-server

有没有办法在不更改(或添加)索引的情况下避免更新查询死锁?

以下查询始终生成死锁

update table1
set Batch_ID=1
where item_id in (select top 300 t1.item_id
                        From    table1 t1 inner join table2 t2 on t1.item_id=t2.item_id
                         inner join table3 t3 on t1.item_ID=t3.item_ID
                        Where   IsNull(t3.item_Delivered,0) = 0
                                And t1.TBatch_ID is Null
                                And t2.Shipper_ID = 2
                                And DateDiff(day,t1.TShipping_Date,getdate()) < 90
                                And (
                                        DateDiff(minute,IsNull(t1.LastTrackingDate,DateAdd(day,-2,GetDate())),getdate()) > 180
                                        OR (DateDiff(minute,IsNull(t1.LastTrackingDate,DateAdd(day,-2,GetDate())),getdate()) > 60 And IsNull(t3.item_Indelivery,0) = 1)
                                )
                                    And t2.Customer_ID not in (700,800)
                        Order By    t1.LastTrackingDate, t2.Customer_ID)

通常我在select query(reader)上使用set transaction isolation level read uncommitted,但在这种情况下它是一个更新查询(writer)。所以我不能应用相同的推理(隔离级别)。

有没有办法为子查询设置事务隔离级别(仅适用于select)??

我可以为子查询的select子句中的每个表添加WITH(NOLOCK)吗?

由于

1 个答案:

答案 0 :(得分:0)

查询似乎在满足特定条件的前300行中将Batch_ID列从NULL切换为1。

此更新容易出现死锁,因为如果两个连接同时运行相同的查询,则两个查询都会找到重叠的table1行,并且两者都会尝试更新(在返回的行之间存在竞争条件)子查询和外部更新)。

Re:(NOLOCK) - 不,读取未提交将导致更加不可预测的行为。一种选择是通过提高锁定悲观性来同步对更新的并发调用,这样任何并发连接都将被阻塞,直到第一个连接的批处理300完成标记为止,例如:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
update table1
set Batch_ID=1
where item_id in (select top 300 t1.item_id
                  From    table1 t1 (WITH XLOCK)  ...
SET TRANSACTION ISOLATION READ COMMITTED;