我正在尝试将 1,500,000 条记录插入表中。我在插入过程中面临表锁定问题。所以我想出了下面的批量插入。
DECLARE @BatchSize INT = 50000
WHILE 1 = 1
BEGIN
INSERT INTO [dbo].[Destination]
(proj_details_sid,
period_sid,
sales,
units)
SELECT TOP(@BatchSize) s.proj_details_sid,
s.period_sid,
s.sales,
s.units
FROM [dbo].[SOURCE] s
WHERE NOT EXISTS (SELECT 1
FROM dbo.Destination d
WHERE d.proj_details_sid = s.proj_details_sid
AND d.period_sid = s.period_sid)
IF @@ROWCOUNT < @BatchSize
BREAK
END
我在 Destination
表 (proj_details_sid ,period_sid )
上有一个聚集索引。 NOT EXISTS
部分只是为了限制插入的记录再次插入到表中
我做得对吗,这会避免表锁吗?或者有没有更好的方法。
注意: 所用时间或多或少与批处理和没有批处理插入相同
原文由 Pரதீப் 发布,翻译遵循 CC BY-SA 4.0 许可协议
锁升级不太可能与您声明的
SELECT
部分有关。这是 插入大量行的自然结果
您可以通过跟踪 Profiler 中的锁升级事件或简单地尝试以下不同的批处理大小来轻松地看到这一点。对我来说
TOP (6228)
显示持有 6250 个锁,但TOP (6229)
随着锁升级开始,它突然下降到 1。确切的数字可能会有所不同(取决于数据库设置和当前可用的资源)。使用反复试验来找到出现锁定升级的阈值。您正在插入 50,000 行,因此几乎可以肯定会尝试锁定升级。
这篇文章 如何解决由 SQL Server 中的锁升级引起的阻塞问题 已经很老了,但是很多建议仍然有效。
另一种选择是
ALTER TABLE blah SET (LOCK_ESCALATION = DISABLE)
但这仍然不是很有针对性,因为它会影响对表的所有查询,而不仅仅是这里的单一场景。所以我会选择选项 1 或可能的选项 2 并打折其他选项。