这是我的场景:我们有一个数据库,我们称之为Logging,其中一个表保存来自Log4Net的记录(通过MSMQ)。 db的恢复模式设置为Simple:我们不关心事务日志 - 它们可以翻转。
我们有一项工作使用sp_spaceused中的数据来确定我们是否达到了特定的大小阈值。如果超过阈值,我们将确定需要删除多少行以将大小降低到该阈值的x%。 (顺便说一下,我使用exec sp_spaceused MyLogTable
,TRUE
来获取行数和粗略近似的平均大小,尽管我不相信这是最好的方法。但是,这是一个不同的问题。)
然后我尝试通过循环调用基本上执行此操作的sproc来删除删除(例如,每次5000次):
DELETE TOP (@RowsToDelete) FROM [dbo].[MyLogTable]
直到我删除了需要删除的内容。
问题在于:如果要删除大量行,则事务日志文件会填满。我可以通过运行来观察它的成长
dbcc sqlperf (logspace)
让我感到困惑的是,当作业失败时,所有已删除的行都会回滚。换句话说,看起来所有的块都在隐式事务中被包装(不知何故)。
我已尝试明确设置隐式事务,将每个DELETE语句包装在BEGIN和COMMIT TRAN中,但无效:要么所有已删除的块都成功,要么根本没有。
我知道简单的答案是,让您的日志文件足够大,以处理您可能删除的最大可能数量的记录,但是,为什么这会被视为单个事务?
很抱歉,如果我错过了一些简单的事情,但我看了很多关于日志文件增长,恢复模式等的帖子,我无法弄清楚这一点。
另一件事:一旦作业失败,日志文件在退回之前会持续一段时间保持在95-100%左右。但是,如果我跑
checkpoint
dbcc dropcleanbuffers
它下降到约5%的利用率。
TIA。
答案 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
我不得不承认我很困惑。我不是数据库大师,但我认为我已经理解了这一点......