【发布时间】:2011-04-06 20:33:03
【问题描述】:
我正在测试一个同时删除很多很多记录的过程。不能TRUNCATE TABLE,因为里面有记录需要保留。
因为体积的原因,我把delete分成了类似这样的循环:
-- 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 语句应该已经完成了,我认为这意味着任何页面拆分也完成了。
为什么 DELETE 循环会针对自身遇到锁定超时?
进程是否有办法避免此锁定超时或检测到可以安全恢复?
这是在 SQL Server 2005 上。
-- 编辑--
我将 Lock:Timeout 事件添加到分析器。删除期间 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 Trace 中的各种锁定事件以查看是否可以取消选择正在发生的事情?
-
刚刚做了,谢谢你提到这一点。我在上面添加了锁定超时信息。不确定究竟是什么被锁定。
-
另一个编辑:在锁定超时后立即添加了一些 sp_lock 信息。
标签: sql sql-server sql-server-2005 locking