2011-12-29 27 views
7

對SQL語句中要刪除的行數應該設置什麼限制?SQL DELETE - 最大行數

我們需要刪除1到幾十萬行,並且需要應用某種最佳實踐限制,以便在每次我們清空垃圾籃時不會絕對殺死SQL服務器或填寫日誌。

此問題不是特定於任何類型的數據庫。

+0

這樣模糊的問題無法回答。沒有銀彈 – zerkms 2011-12-29 20:59:12

+0

我們使用批量夜間移動作業將記錄從一個表格移動到另一個表格。我們運行的批量爲10,000,性能影響可以忽略不計。 – Dimitri 2011-12-29 21:01:51

+0

您需要嘗試添加一些限制並監控服務器性能以獲得最佳答案。 – piotrekkr 2011-12-29 21:01:54

回答

12

這是一個非常廣泛的問題,基本歸結爲「它取決於」。影響它的因素包括:

  • 什麼是您的併發級別?刪除語句在受影響的行上放置排他鎖。取決於數據庫引擎,刪除的數據分佈等,可能會升級到頁面或整個表格。您的數據讀取器在刪除期間是否可以被阻止?

  • 刪除語句有多複雜?你還加入了多少個其他表,還是有複雜的WHERE子句?有時,刪除行的標識可能比刪除本身更「昂貴」,因此一個大的刪除可能會「更便宜」。

  • 你是否害怕死鎖?當你減小刪除的大小時,你的死鎖「腳印」就會減少。理想情況下,單行刪除將始終成功。

  • 你關心吞吐量性能嗎?與任何SQL語句一樣,通常會有一定量的開銷(連接內容,查詢解析,返回結果等)。從單一連接的角度來看,1000行刪除將比1000 x 1行刪除更快。

  • 不要忘記索引維護開銷,碎片清理或任何觸發器。它們也會影響你的系統。

總的來說,我的基準線每條語句有1000行。與我合作過的大多數系統(子企業)最終每刪除500到5000條記錄的甜點。我喜歡做這樣的事情:

set rowcount 500 

select 1 -- Just to force @@rowcount > 0 
while @@ROWCOUNT > 0 
delete from [table] 
    [where ...] 
+0

+1,會補充說,如果你刪除了一定數量的行,有時候更好地處理它;所以刪除10然後100然後1000作爲數據庫緩存了一些工作,這kind'a你點4 – Ben 2011-12-29 22:33:24

+0

你適合在一般有很多更多的支持代碼做什麼,但一個「虛擬」斜坡上升。我還發現,試圖達到「最大」行/秒刪除是相當無用的。更好的方法是找到一個可接受的窗口(比如15秒),並嘗試一次刪除多少行。在註釋僞代碼中:挑選100行以刪除。刪除並獲取時間信息。如果時間<15秒,則選擇ROWS * 1.5刪除;否則選擇行* 0.5刪除。重複。這將擴大您的基於時間的吞吐量,並且對數據庫上的其他活動很敏感。 – jklemmack 2012-01-03 20:33:20

+0

對於未來的讀者,請參閱下面的@SQLPhil的答案。基於Microsoft Books Online,未來版本的SQL Server將不會授予'INSERT','UPDATE'或'DELETE'語句的'SET ROWCOUNT'。最好使用'TOP'語法。 – jklemmack 2016-12-06 15:48:16

0

一般的答案是刪除該表並重新創建它,這是一個性能良好的解決方案,而是適用於全表

+0

如果有過程,函數,視圖等依賴於你要刪除表時會發生什麼?根本沒有任何理由,你會使他們無效。 – Ben 2011-12-29 22:30:59

1

除非你有很多觸發器或完整性約束的驗證,刪除不該手術費用不高。

但是,如果你關心性能,我最初的預感是將相應的行標記爲已刪除,然後在定期清理期間將其物理刪除。但是我並不是很喜歡這個,因爲你必須改變該表上的任何查詢來排除邏輯上的 - 但不是物理上刪除的行。

1

每當我看到經常刪除大量行的散裝數據庫,這讓我想起了數據模型或處理的設計是不是最佳的。爲什麼加載100萬行然後刪除它們?如果您需要執行諸如清除歷史數據之類的操作,請考慮表分區。

+1

羅素。可能有一些原因可能會導致您載入一百萬條記錄;您可以在丟棄原始數據之前執行計算並存儲計算的值。但你確實有一個好點,適當的設計很重要。 – Leons 2011-12-31 17:41:36

4

雖然限制影響的行數您刪除使用SET ROWCOUNT選項,然後進行一個循環是非常好的(和我以前很多時候用它),要知道,從2012年起,SQL這不會是一個選項(見BOL)。

因此,另一個選擇可以是限制使用TOP子句被刪除的行數。即

SELECT 1 

WHILE @@ROWCOUNT > 0 
BEGIN 
    DELETE TOP (#) 
    FROM mytable 
    [WHERE ...] 
END