1

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

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

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

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

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

问题是:如果我有很多行要删除,事务日志文件就会填满。我可以通过跑步看着它成长

dbcc sqlperf (logspace)  

令我困惑的是,当作业失败时,所有已删除的行都会回滚。换句话说,似乎所有块都被(以某种方式)包装在隐式事务中。

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

我知道简单的答案是,使您的日志文件足够大,以处理您曾经删除的尽可能多的记录,但是,为什么这被视为单个事务?

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

另一件事:一旦作业失败,日志文件会在一段时间内保持在 95% - 100% 左右,然后再回落。但是,如果我运行

checkpoint
dbcc dropcleanbuffers

它立即回落到大约 5% 的利用率。

TIA。

4

2 回答 2

0

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

至于“所有删除都回滚”,除了外部事务之外,我没有看到其他解释。您可以发布清理日志的整个代码吗?您如何调用此代码?你的隐式交易设置是什么?

嗯..如果日志增长并且没有自动截断,它也可能表明有一个事务在循环之外运行。你能select @@trancount在你的循环之前或者每次迭代中找出发生了什么吗?

于 2010-04-30T18:17:31.333 回答
0

好吧,我尝试了几件事,但仍然所有删除都会回滚。@@TRANCOUNT我在删除之前和之后都添加了 printint并且计数为零。然而,失败时,所有删除都回滚....我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

我不得不承认我很困惑。我不是数据库专家,但我认为我理解的足够多,可以解决这个问题......

于 2010-05-03T16:51:43.060 回答