我正在测试一次删除许多记录的进程。它不能TRUNCATE TABLE
,因为那里有记录需要保留。超过SQL Server锁定超时删除循环中的记录
因为体积的,我已经打破了删除成类似于这样一个循环:
-- Do not block if records are locked.
SET LOCK_TIMEOUT 0
-- This process should be chosen as a deadlock victim in the case of a deadlock.
SET DEADLOCK_PRIORITY LOW
SET NOCOUNT ON
DECLARE @Count
SET @Count = 1
WHILE @Count > 0
BEGIN TRY
BEGIN TRANSACTION -- added per comment below
DELETE TOP (1000) FROM MyTable WITH (ROWLOCK, READPAST) WHERE MyField = SomeValue
SET @Count == @@ROWCOUNT
COMMIT
END TRY
BEGIN CATCH
exec sp_lock -- added to display the open locks after the timeout
exec sp_who2 -- shows the active processes
IF @@TRANCOUNT > 0
ROLLBACK
RETURN -- ignoring this error for brevity
END CATCH
MyTable的是聚集表。 MyField位于聚簇索引的第一列。它表示记录的逻辑分组,所以MyField = SomeValue
通常选择许多记录。我不关心他们被删除的顺序,只要一次处理一个组。这张桌子上没有其他的索引。
我添加了ROWLOCK
提示以尽量避免我们在生产中看到的锁升级。我添加了READPAST
提示以避免删除其他进程锁定的记录。这绝不应该发生,但我正在努力安全。
问题:有时这回路达到锁定超时1222“锁请求超时周期超出”当它是唯一运行的。
我认为在我测试此过程时没有其他活动,因为它是我自己的开发者框,没有其他人连接,没有其他进程在运行,并且分析器显示没有活动。
我可以在一秒钟之后重新运行相同的脚本,它会从中断的地方开始,快乐地删除记录 - 直到下一次锁定超时。
我试过BEGIN TRY
/BEGIN CATCH
忽略1222错误并重试删除,但它立即再次失败,并出现相同的锁定超时错误。如果我在重试之前添加一个很短的延迟,它也会再次失败。
我假定锁定超时是因为像页拆分,但我不知道为什么,这将与当前循环迭代冲突。之前的删除声明应该已经完成,我认为这意味着任何页面拆分也已完成。
为什么DELETE环撞到本身锁定超时?
有没有办法可以避免这种锁定超时或检测到它可以安全地恢复?
这是SQL Server的2005
- 编辑 -
我加了锁:超时事件探查器。它在删除超时上的PAGELOCK:
Event Class: Lock:Timeout
TextData: 1:15634 (one example of several)
Mode: 7 - IU
Type: 6 - PAGE
DBCC PAGE报告这些页是外部的主数据库(ID 1)的范围内的。
- 编辑2 -
我加入BEGIN TRY
/BEGIN CATCH
跑在catch块的exec sp_lock
。这里是我看到的:
spid dbid ObjId IndId Type Resource Mode Status
19 2 1401108082 1 PAG 1:52841 X GRANT (tempdb.dbo.MyTable)
19 2 1401108082 0 TAB IX GRANT (tempdb.dbo.MyTable)
Me 2 1401108082 0 TAB IX GRANT (tempdb.dbo.MyTable)
Me 1 1115151018 0 TAB IS GRANT (master..spt_values) (?)
SPID 19是一个SQL Server任务管理器。为什么其中一个任务管理器会在MyTable上获取锁?
你试过跟踪SQL跟踪的各种锁定事件,看看你能不能拆洗发生了什么? – 2011-04-06 22:13:46
刚刚做了,谢谢你提到这一点。我在上面添加了锁定超时信息。不确定究竟是什么被锁定。 – 2011-04-06 22:41:56
另一个编辑:在锁定超时后立即添加一些sp_lock信息。 – 2011-04-06 22:58:57