2010-04-30 67 views
1

這裏是我的場景:我們有一個數據庫,我們稱它爲Logging,並帶有一個表格,該表格包含來自Log4Net(通過MSMQ)的記錄。數據庫的恢復模式設置爲簡單:我們不關心事務日誌 - 它們可以翻轉。Sql Server:分塊刪除仍填滿事務日誌;失敗時,所有刪除都回滾 - 爲什麼?

我們有一個工作,它使用來自sp_spaceused的數據來確定我們是否達到了一定的大小閾值。如果超過閾值,我們確定需要刪除多少行才能將大小降至該閾值的百分之x。 (順便說一句,我使用exec sp_spaceused MyLogTable,TRUE來獲得行數和他們的平均大小的粗略近似值,雖然我不相信這是最好的方式去做,但這是一個不同的問題。 )

然後我嘗試塊刪除(比如說,5000在時間)通過循環到一個存儲過程,基本上做了這樣的電話:

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

,直到我已經刪除了需要刪除的內容。

問題出在這裏:如果我有很多要刪除的行,則事務日誌文件填滿。我可以看它通過運行增長

dbcc sqlperf (logspace) 

令我困惑的是,當作業失敗時,所有刪除的行都會回滾。換句話說,看起來所有的塊都被包裝在一個隱含的事務中(以某種方式)。

我已經試過明確設置隱式事務,將每個DELETE語句包裝在BEGIN和COMMIT TRAN中,但無濟於事:要麼所有刪除的塊都成功,要麼根本沒有。

我知道一個簡單的答案是,讓您的日誌文件足夠大,以處理儘可能多的記錄,但您仍然可以將其視爲單個事務處理?

對不起,如果我錯過了一件容易的事情,但我已經看過很多關於日誌文件增長,恢復模式等的帖子,我無法弄清楚這一點。

還有一件事:一旦作業失敗,日誌文件會在回落之前保持在95-100%的滿量程。但是,如果我運行

checkpoint 
dbcc dropcleanbuffers 

它會直接回落到約5%的利用率。

TIA。

回答

0

簡單恢復模型中的日誌文件會在每個檢查點自動截斷。您可以像在循環結束時一樣手動調用檢查點,但您也可以在每次迭代中執行此操作。檢查點的頻率默認由SQL Server根據恢復間隔設置自動確定。

只要'所有刪除都回滾',我不會看到其他解釋,而是一個外部事務。你能發佈清理日誌的完整代碼嗎?你如何調用這段代碼? 您對隱式交易的設置是什麼?

嗯..如果日誌增長並且不會自動截斷,它也可能表明有一個事務正在循環之外運行。你可以在你的循環之前select @@trancount,也許每次迭代找出發生了什麼?

+1

Piotr,感謝您的建議秒。事實上,我一直在執行查詢分析器的「驅動程序」存儲過程。關於外部事務的問題讓我想知道,查詢分析器默認情況下是否設置了implicit_transactions?我檢查了Profilier並沒有看到。但是,我將在查詢分析器會話中再次嘗試使用SET IMPLICIT_TRANSACTIONS OFF,並查看是否有所作爲(無論全部或部分是否會在失敗時回滾)。當我進行這個測試時,我會重新發布。 謝謝你,Paul – 2010-04-30 19:06:42

0

那麼,我嘗試了幾件事情,但仍然全部刪除得到回滾。我在刪除之前和之後添加了printint @@TRANCOUNT,並且計數爲零。然而,如果失敗,所有刪除操作都會回滾....我在幾個地方添加了0​​(包括我在查詢分析器的初始調用中,但似乎沒有幫助,這是正在調用的存儲過程的主體(我已@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 

我不得不承認,我百思不得其解我不是一個數據庫大師,但我認爲我足夠了解這一點......

+0

嗯,我真的很討厭承認這一點,但在@ RowsToDelete中,我通過了要刪除的總行數 - 而不是我的塊大小。嘆。另外幾張印刷聲明和另一組眼睛引發了我的錯誤......問題解決了。 – 2010-05-03 18:37:26