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