【发布时间】:2015-03-11 14:36:18
【问题描述】:
我的应用程序每晚运行一个清除过程,以从我的 OLTP 应用程序的主表中删除旧记录。我在清除过程中遇到锁升级,它阻止并发插入到表中,因此我修改了清除过程以循环并删除 4900 块中的记录,这应该远低于 SQL Server 的锁升级阈值 5000。虽然锁升级大大减少了,SQL Server Profiler 仍然在循环中的以下 DELETE 语句上报告偶尔的锁升级:
-- outer loop increments @BatchMinId and @BatchMaxId variables
BEGIN TRAN
-- limit is set at 4900
DELETE TOP (@limit) h
OUTPUT DELETED.ChildTable1Id,
DELETED.ChildTable2Id,
DELETED.ChildTable3Id,
DELETED.ChildTable4Id
INTO #ChildRecordsToDelete
FROM MainTable h WITH (ROWLOCK)
WHERE h.Id >= @BatchMinId AND h.Id <= @BatchMaxId AND h.Id < @MaxId AND
NOT EXISTS (SELECT 1 FROM OtherTable ot WHERE ot.Id = h.Id);
-- delete from ChildTables 1-4 (no additional references to MainTable)
COMMIT TRAN;
-- end loop
SQL Server Profiler 中报告的锁升级事件(应该是escalated lock count)的“IntegerData2”列范围从 10197 到 10222,看起来不接近 4900 的任何倍数(我的清除批量大小)加上 1250 的任意倍数 (number of additional locks SQL Server may take before attempting escalation)。
鉴于我明确地将 DELETE 语句限制为 4900 行,如何获得更多的锁,尤其是 SQL Server 升级为表锁的程度?在我完全禁用此表上的锁升级之前,我想了解这一点。
【问题讨论】:
-
我不会禁用锁升级 - 它可能会导致其他问题。有关禁用锁升级的非常清晰的讨论,请参阅sqlpassion.at/archive/2014/02/25/lock-escalations 以 1000 的批量大小进行清除怎么样?根据我的经验,您不会看到主要的速度差异。
-
我认为,尽管您尽了最大的努力,SQL Server 可能会在选择升级锁时决定升级锁。删除是否有及时性要求?从逻辑上讲,批量越小,锁升级的可能性就越小。还能再减吗?此外,无论如何都可以调整查询 - 这可能会降低锁定升级的可能性。
-
我不是这方面的专家,但如果你有非聚集索引,我认为这些索引也需要锁定和删除 + 可能还有聚集索引中的一些页面。这可以解释吗?
-
@benjaminmoskovits 我将禁用锁升级仅作为最后的手段。我可以尝试减小批量大小,但即使这样可行,我也想了解为什么比锁升级阈值小 100 还不够好,但比锁升级阈值小 4000 就足够了。
-
@DanSaunders 据我了解,SQL Server 可能会将锁升级推迟到每个对象超过 5000 个锁,但它可能不会任意升级到少于 5000 个锁。
标签: sql-server sql-server-2012 locking