删除表中的行会导致LOCKS

时间:2012-01-25 08:01:39

标签: sql-server sql-server-2008 tsql

我正在运行以下命令从大表(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吗?这将如何影响日志大小(我们只有很少的硬盘空间用于大对数增长)。

有什么建议吗?

7 个答案:

答案 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