Sql Server:分块删除仍然填满了事务日志;在失败时,所有删除都会回滚 - 为什么?

时间:2010-04-30 14:39:35

标签: sql-server tsql transactions implicit transaction-log

这是我的场景:我们有一个数据库,我们称之为Logging,其中一个表保存来自Log4Net的记录(通过MSMQ)。 db的恢复模式设置为Simple:我们不关心事务日志 - 它们可以翻转。

我们有一项工作使用sp_spaceused中的数据来确定我们是否达到了特定的大小阈值。如果超过阈值,我们将确定需要删除多少行以将大小降低到该阈值的x%。 (顺便说一下,我使用exec sp_spaceused MyLogTableTRUE来获取行数和粗略近似的平均大小,尽管我不相信这是最好的方法。但是,这是一个不同的问题。)

然后我尝试通过循环调用基本上执行此操作的sproc来删除删除(例如,每次5000次):

DELETE TOP (@RowsToDelete) FROM [dbo].[MyLogTable]  

直到我删除了需要删除的内容。

问题在于:如果要删除大量行,则事务日志文件会填满。我可以通过运行来观察它的成长

dbcc sqlperf (logspace)  

让我感到困惑的是,当作业失败时,所有已删除的行都会回滚。换句话说,看起来所有的块都在隐式事务中被包装(不知何故)。

我已尝试明确设置隐式事务,将每个DELETE语句包装在BEGIN和COMMIT TRAN中,但无效:要么所有已删除的块都成功,要么根本没有。

我知道简单的答案是,让您的日志文件足够大,以处理您可能删除的最大可能数量的记录,但是,为什么这会被视为单个事务?

很抱歉,如果我错过了一些简单的事情,但我看了很多关于日志文件增长,恢复模式等的帖子,我无法弄清楚这一点。

另一件事:一旦作业失败,日志文件在退回之前会持续一段时间保持在95-100%左右。但是,如果我跑

checkpoint
dbcc dropcleanbuffers

它下降到约5%的利用率。

TIA。

2 个答案:

答案 0 :(得分:0)

简单恢复模型中的日志文件会在每个检查点自动截断。您可以像在循环结束时一样手动调用检查点,但您也可以在每次迭代时执行此操作。默认情况下,检查点的频率由sql server根据恢复间隔设置自动确定。

就“所有删除都被回滚”而言,我没有看到其他解释,只有外部交易。你能发布清理日志的整个代码吗?你如何调用这段代码? 您对隐式交易的设置是什么?

嗯..如果日志增长并且没有自动截断,它也可能表示在循环外部运行了一个事务。您可以在循环之前select @@trancount,也许每次迭代都可以找出正在发生的事情吗?

答案 1 :(得分:0)

好吧,我尝试了几件事,但仍然会删除所有删除。我在删除之前和之后添加了printint @@TRANCOUNT,我得到零作为计数。然而,在失败时,所有删除都会被回滚....我在几个地方添加了SET IMPLICIT_TRANSACTIONS OFF(包括我在查询分析器中的初始调用中,但这似乎没有帮助。这是存储过程的主体被调用(我已将@RowsToDelete设置为5000和8000):

  SET NOCOUNT ON;
  print N'@@TRANCOUNT PRIOR TO DELETE: ' + CAST(@@TRANCOUNT AS VARCHAR(20));

  set implicit_transactions off;
  WITH RemoveRows AS 
  (
    SELECT ROW_NUMBER() OVER(ORDER BY [Date] ASC) AS RowNum
    FROM [dbo].[Log4Net]
  )

  DELETE FROM RemoveRows
  WHERE RowNum < @RowsToDelete + 1

  print N'@@TRANCOUNT AFTER DELETE: ' + CAST(@@TRANCOUNT AS VARCHAR(20));

从这个t-sql调用它:

WHILE @RowsDeleted < @RowsToDelete
BEGIN
 EXEC [dbo].[DeleteFromLog4Net] @RowsToDelete 
 SET @RowsDeleted = @RowsDeleted + @RowsToDelete
 Set @loops = @loops + 1
 print 'Loop: ' + cast(@loops as varchar(10))
END

我不得不承认我很困惑。我不是数据库大师,但我认为我已经理解了这一点......