2011-11-23 118 views
3

有一个每小时运行一次的进程必须插入​​到table1中,但是当下面的查询正在运行时,插入会被阻止。谁能解释为什么?我意识到锁提示就是这样,提示和SQL可能会选择忽略它们。 table1有300m行,我需要更新ColumnA中的值。我正在做大块的事情来帮助回滚,以防止进程被停止,因此while循环。此查询为什么阻止插入?

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
go 

declare @start bigint 
declare @end bigint 
declare @max bigint 
declare @step int 

set @step = 50000 
set @start = 17953095 
set @end = @start + @step 
set @max = @start + 2000000 

while (@end < @max) 
begin 

waitfor delay '00:00:10' 

begin transaction 

update [table1] with (ROWLOCK) 
set [table1].[ColumnA] = [table2].[ColumnA] 
from [table2] (nolock) 
where [table2].[ColumnB] = [table1].[ColumnB] 
and [table1].ID >= @start 
and [table1].ID < @end 

commit transaction 

print @end 

if @end >= @max 
begin 
    break 
end 

set @start = @end 
set @end = @end + @step 

end 

print @end 

我可以这样做另一种方式,因此它不会阻止插入或其他更新?除了上面的查询外,其他任何内容都不需要使用ColumnA。

回答

2

您可以尝试使用较小的批量大小。 SQL Server的升级行锁直到表锁当超过一定的阈值,每MSDN

数据库引擎不会升级行或键范围锁页 锁,而是直接升级他们到表锁。
...
...当锁升级不是 禁用
锁升级时触发以下任一条件存在,通过使用ALTER TABLE SET LOCK_ESCALATION选项表, :

一单个Transact-SQL语句在单个非分区表或索引上获取至少5,000个锁。

单个Transact-SQL语句在分区表的一个分区 上获取至少5,000个锁,并且ALTER TABLE SET LOCK_ESCALATION选项设置为AUTO。

数据库引擎实例中的锁数量超过内存或配置阈值的 。

如果由于锁冲突而无法升级锁,数据库将在每获取1,250个新锁 时周期性触发锁升级。

您目前的50,000个批量大小远远超过该阈值。

另一件需要考虑的问题是您是否有合适的索引来适应您的WHERE子句 - 请确保尽可能优化。

+0

所以你认为减少到5K的步骤会有帮助吗?我能否看到桌上的桌子锁是否被取出? – ILovePaperTowels

+0

+1正确 - 在桌子上进行超过5000次的更新,并且您获得了独占(X)表锁! –

+0

或者我应该改变锁升级? – ILovePaperTowels