2

我正在 SQL Enterprise Manager 2000 上完成一项工作,以复制和删除几个数据库表中的记录。我们已经运行了一个直接的批量复制和删除存储过程,但它可能会在数百万行上运行它,因此会挂起服务器。我有兴趣尝试一次以 100 个记录块运行该服务,因此服务器不会停止运行(这是一个实时 Web 数据库)。我希望这项服务每晚运行一次,这就是我将它放在代理工作中的原因。有没有办法循环调用实际执行复制和删除的存储过程,然后在每次调用之间“休眠”以让服务器有时间赶上?我知道有 WAITFOR 命令,但我不确定这是否会保留处理器或让它同时运行其他查询。

谢谢!

4

3 回答 3

2

将您的删除“分块”是删除大量数据而不会使事务日志文件膨胀的首选方法。BradC 的帖子就是一个合理的例子。

管理此类循环最好在单个存储过程中完成。为了随着时间的推移分散这些工作,我仍然会将其保留在程序中。如果您认为有必要处理可能的并发问题,则在循环中插入 WAITFOR 将在每组删除之间放置一个“暂停”。使用 SQL 代理作业来确定过程何时开始 - 如果您需要确保它在某个时间停止,也可以将其放入循环中。

我对这段代码的看法是:

--  NOTE: This is a code sample, I have not tested it
CREATE PROCEDURE ArchiveData

    @StopBy DateTime
    --  Pass in a cutoff time.  If it runs this long, the procedure will stop.
AS

DECLARE @LastBatch  int

SET @LastBatch = 1
--  Initialized to make sure the loop runs at least once


WHILE @LastBatch > 0
 BEGIN

    WAITFOR DELAY '00:00:02'
    --  Set this to your desired delay factor

    DELETE top 1000  --  Or however many per pass are desired
     from SourceTable
    --  Be sure to add a where clause if you don't want to delete everything!

    SET @LastBatch = @@rowcount

    IF getdate() > @StopBy
        SET @LastBatch = 0

 END

RETURN 0

唔。重读您的帖子意味着您想先将数据复制到某处,然后再删除它。为此,我设置了一个临时表,并在循环内首先截断临时表,然后复制前 N 个项目的主键,通过连接到临时表插入“存档”表,然后也通过连接到临时表来删除源表。(只是比直接删除复杂一点,不是吗?)

于 2009-10-21T14:46:05.983 回答
1

不用担心循环之间的等待,SQL Server 应该处理您的维护工作和服务器上的常规活动之间的争用。

在这些类型的情况下,真正导致问题的原因是整个删除过程在单个事务中同时发生。这会炸毁数据库的日志,并可能导致听起来像您遇到的各种问题。

使用这样的循环删除可管理的块:

DECLARE @i INT
SET @i = 1

SET ROWCOUNT 10000

WHILE @i > 0
BEGIN
    BEGIN TRAN
        DELETE TOP 1000 FROM dbo.SuperBigTable
        WHERE RowDate < '2009-01-01'
    COMMIT

    SELECT @i = @@ROWCOUNT
END
SET ROWCOUNT 0

您可以为您的副本使用类似的逻辑。

于 2009-10-21T14:17:59.053 回答
0

WAITFOR会让其他进程“试一试”。我已经使用这种技术来阻止大型 DELETE 锁定机器。创建一个 WHILE 循环,删除一个行块,然后等待几秒钟(或更少,只要合适)。

于 2009-10-21T14:15:39.207 回答