2011-05-05 64 views
7

我正在編寫一個過程,用於刪除n天之前幾張表中的所有行。從SQL Server中刪除大量的行 - 以高效和非鎖定的方式

一個死簡單的查詢很容易編寫

DELETE FROM [myTable] 
WHERE [Created] < GETDATE()-30 

的一個問題是沒有對日期字段沒有索引 - 我可以添加一個,但我的工作圍繞它做類似:

SELECT @var = MAX([ID]) FROM myTable WHERE Created < GETDATE()-30; 
DELETE FROM myTable WHERE ID < @var 

這似乎是一個可接受的方法嗎?

問題是表是巨大的,而且這個查詢將會刪除每次運行可能有幾十萬行。

在一個(稍慢)的測試服務器上運行它需要一個小時左右的時間,並從試圖讀取/寫入其他進程的表中查殺表。

我並不太在乎它需要一段時間才能運行(雖然速度更快) - 但是我不能讓它在運行時將表鎖定一個小時,因爲存在不斷的讀/寫操作(主要是寫)。

我的數據庫知識是相當基本的,因爲我是一個編碼員而不是dba。

有人可以給我一個體面的方法來執行此任務 - 以最有效的方式。

+0

爲什麼不簡單地選擇要刪除到臨時表中的記錄,然後創建一個遊標以刪除每次運行中臨時表中的幾條記錄?然後你有很多小的刪除語句不應該鎖定你的表。 – Tejs 2011-05-05 21:58:17

+0

刪除舊的分區。如果你沒有分區,你應該看看... – peufeu 2011-05-05 22:11:19

回答

6

你在找什麼是一個基於分區的滑動窗口:How to Implement an Automatic Sliding Window in a Partitioned Table on SQL Server 2005。按天對錶格進行分區,並且可以在午夜的單個分區切換操作中有效地放下整整一天。分區切換基本上是瞬時的。

如果您想要一個開銷稍低的解決方案(分區會對整個應用程序造成嚴重的後果和漣漪,尤其是索引必須對齊時,這是快速切換操作的要求),那麼您必須設計您的按照這個操作的模式。憑藉99.99%的信心,我可以說您的myTable必須的最左邊的集羣密鑰是Created字段。這將允許有效的批量刪除(delete top (2500) from myTable where Created < ...)。有很多原因讓你想要批量生產(一次最多2500個),最重要的是你必須避免鎖升級,並且你必須將任何單個交易的規模保持在合理範圍內。

3

您的方法將遭受與正常刪除相同的疾病 - 您在[Created]上沒有索引。因此你的方法更加複雜。

我建議您創建所述索引並嘗試在您的測試服務器上正常刪除。

另一個建議 - 通過調度程序在正常工作時間以外運行。

0

創建索引並在辦公時間以外執行刪除操作可能是最好的選擇。但是,如果它們不是選項,則可以根據查詢創建視圖並刪除該視圖,因此僅需要引用表一次而不是兩次,從而加快IO操作。

create view v1 as (select * FROM myTable WHERE Created < GETDATE()-30;) 
delete from v1 
+0

這將沒有影響。除了索引視圖之外,當使用視圖時,視圖定義被展開並且查詢按照正常方式運行(與以手動方式手動展開視圖定義的方式非常相似)。 – Justin 2011-05-05 23:02:16

3

爲了提高性能,您應該查看在創建字段上創建索引,如果這是您想要經常執行的操作。

那麼你可以使用

DELETE FROM myTable 
WHERE Created < GETDATE()-30 

我見過多小時的過程減少到幾秒鐘用適當的指標和統計數據的補充。

索引很容易創建,並且可能有工具可用於建議索引並提供語法。示例:MS SQL 2005 Management Studio中的SQL Tuning Advisor。

+0

如果您發佈代碼,XML或數據樣本,請**在文本編輯器中突出顯示這些行,然後單擊編輯器工具欄上的「代碼樣本」按鈕(「{}」)以精確地設置格式並進行語法高亮顯示! – 2011-05-06 04:54:31

2

我會假設你不能索引創建的列(因爲那是另外開始的邏輯地方)。基於這個假設,你將會遇到性能和鎖定問題。但是,由於您使用的是SQL 2005,因此您可以利用本文中指定的一些新功能: http://nayyeri.net/reduce-locks-for-delete-and-update-commands-in-sql-server-2005-with-top-clause

基本上,創建一個查詢來選擇要影響的所有記錄。將行標識符(索引)寫入臨時表。根據標識符將臨時錶鏈接到要從中刪除的表格。然後使用此處指定的批次刪除一次刪除組。

通過這種方式,您可以根據您的日期標準創建一個臨時表(由於非索引,它不會很有效,但您可以設置NOLOCK,因此它不會鎖定您)。然後,您可以批量刪除該表以減少對實際刪除的鎖定。