我正在运行以下命令从大表(1.5亿行)中批量删除行:
DECLARE @RowCount int
WHILE 1=1
BEGIN
DELETE TOP (10000) t1
FROM table t1
INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey
WHERE t1.YearProcessed <= 2007
SET @RowCount = @@ROWCOUNT
IF (@RowCount < 10000) BREAK
END
此表格高度使用。但是,它正在删除记录,但它也会导致某些记录的锁定,从而给用户带来错误(在我们所处的环境中这是不可接受的)。
如何在不导致锁定的情况下删除旧记录?我应该将批量的大小从10000记录减少到1000吗?这将如何影响日志大小(我们只有很少的硬盘空间用于大对数增长)。
有什么建议吗?
答案 0 :(得分:7)
我在过去看到过类似的零星问题,即使是小批量的5000条记录,锁定仍然会发生。在我们的例子中,每个删除/更新都包含在它自己的Begin Tran ... Commit循环中。要纠正问题,
的逻辑WaitFor DELAY '00:00:00:01'
被放置在每个循环的顶部并且纠正了问题。
答案 1 :(得分:4)
首先 - 看起来您的DELETE正在执行Clustered Index Scan,我建议您执行以下操作:
create index [IX.IndexName] ON t1(YearProcessed, PrimaryKey)
第二 - 是否有需要加入t2表?
然后使用以下查询删除行,假设您的PrimaryKey列的类型为INT:
declare @ids TABLE(PrimaryKey INT)
WHILE 1=1
BEGIN
INSERT @ids
SELECT top 10000 DISTINCT t1.PrimaryKey
FROM table t1
INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey
WHERE t1.YearProcessed <= 2007
IF @@ROWCOUNT = 0 BREAK
DELETE t1
WHERE PrimaryKey in (Select PrimaryKey from @ids)
delete from @ids
END
如果不需要,请不要忘记从连接中删除t2表
如果它仍然导致锁定 - 那么降低每轮中删除的行数
答案 2 :(得分:1)
我认为你走在正确的轨道上。
看看这两篇文章:
和
http://www.dbforums.com/microsoft-sql-server/985516-deleting-without-locking.html
在运行删除之前,请检查估计的查询计划以查看是否存在 正在做索引寻找删除,或仍在做一个完整的表 扫描/访问。
答案 3 :(得分:0)
除了其他建议(旨在减少删除期间完成的工作)之外,您还可以将SQL Server配置为在对表执行删除时不阻止其他读取器。
这可以通过使用SQL Server 2005引入的“快照隔离”来完成:
http://msdn.microsoft.com/en-us/library/ms345124%28v=sql.90%29.aspx
答案 4 :(得分:0)
如果您有任何带有级联删除的内容,请确保将其编入索引。
突出显示DELETE查询并单击Display estimated execution plan
将显示建议的索引 - 在我的情况下包括一些级联删除。
为那些使删除速度更快的添加索引 - 但我仍然不会尝试一次删除所有行。
答案 5 :(得分:0)
我找到的最佳方式是表单asp.net DeleteExpiredSessions。你执行READUNCOMMITTED选择并将记录放在临时表中,而不是使用CURSOR删除记录。
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25" />
答案 6 :(得分:0)
试试这个,
DECLARE @RowCount int
WHILE 1=1
BEGIN
BEGIN TRANSACTION
DELETE TOP (10000) t1
FROM table t1
INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey
WHERE t1.YearProcessed <= 2007
END TRANSACTION
COMMIT TRANSACTION
SET @RowCount = @@ROWCOUNT
IF (@RowCount < 10000) BREAK
END