我在一张不断增长的桌子上运行一个清理工作(每小时)。这项工作运行了大约一个星期没有任何问题。今天我看到工作开始锁定整个桌子。
这是预期的行为吗?可能是在需要删除特定的行数后,它会锁定整个表而不是只需要删除的特定行吗?
提前致谢!
答案 0 :(得分:2)
如果您的查询在同一个表中影响5000行或更多行,则该表在操作期间会被锁定。这是标准的SQL Server行为。基本上每个DELETE都会导致该行的锁定,并且同一个表上的每5000行锁定会导致从一行到另一个表的锁定升级。
答案 1 :(得分:2)
一种可能性是您需要索引要在表中搜索要删除的行的列。如果您没有索引,则SQL Server将在搜索要删除的行时获取更多锁。
我强烈建议在循环中删除小块行。正如其他人所指出的,如果您尝试一次删除超过5,000行,SQL Server会将行锁升级为表锁。一次删除较少的记录 - 比如1000--避免锁定整个表。您的工作可以继续循环删除,直到完成。
循环删除的伪代码如下所示:
declare @MoreRowsToDelete bit
set @MoreRowsToDelete = 1
while @MoreRowsToDelete = 1
begin
delete top (1000) MyTable from MyTable where MyColumn = SomeCriteria
if not exists (select top 1 * from MyTable where MyColumn = SomeCriteria)
set @MoreRowsToDelete = 0
end
或者,您可以查看@@ROWCOUNT
并使用READPAST
提示以避免锁定行:
declare @RowCount int
set @RowCount = 1 -- priming the loop
while @RowCount > 0
begin
delete top (1000) MyTable from MyTable with (readpast) where MyColumn = SomeCriteria
set @RowCount = @@ROWCOUNT
end
请注意,锁定升级阈值取决于其他因素,例如并发活动。如果您经常进行如此多的活动,即使1,000次删除也会升级为表锁,您可以降低一次删除的行数。
答案 2 :(得分:0)
当你更新/删除一行时它会被锁定(到目前为止这么容易),当有很多行需要修改时,每个被锁定一个直到某个时间点,DBMS'决定'切换到'LOCK整个表'正如jean所说,这取决于你的DBMS的许多(通常是可扩展的)参数,并且(通常)恰好获得了更好的性能。
但是有一件坏事:获得“死锁”的机会加剧(我曾经遇到问题或者100%的机会),因为当DBMS切换到“锁定表”时它必须等待对于该表上的其他任务的锁,但是它已经自己(或你的UOW)已经锁定了几千行......
为了避免这种情况,有时如果你“推”一点DBMS并提前锁定整个表(在独占模式下),它会有所帮助。这有助于如果UPDATE / DELETE它自我修改足够的行以使表锁定发生,但在世界上它仍然足够快 - 在你的环境中“足够快”的意思。
另一种避免这种情况的方法是删除/更新每个查询的部分,如果你不依赖于UOW(回滚),但这通常不是清理的问题(如果它被回滚,它的一部分下一次清理,再次),如何做到这一点取决于你的环境