使用SQL代理作业在循环中调用过程

时间:2009-10-21 14:11:43

标签: stored-procedures sql-server-agent

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

谢谢!

3 个答案:

答案 0 :(得分:2)

“Chunkifying”您的删除是删除过多数据而不会使事务日志文件膨胀的首选方法。 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

嗯。重新发布帖子意味着您希望在删除之前先将数据复制到某处。为此,我设置了一个临时表,并在循环内首先截断临时表,然后复制TOP N项的主键,通过连接到临时表插入“archive”表,然后通过连接删除源表到临时表。 (比直接删除要复杂一点,不是吗?)

答案 1 :(得分: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

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

答案 2 :(得分:0)

WAITFOR会让其他进程“开始”。我用这种技术来阻止大型DELETE锁定机器。创建一个WHILE循环,删除一行行,然后WAITFOR几秒钟(或更少,适当的话)。