[英]SQL Server delete performance
我在我們的 .NET web 應用程序中有一個例程,它允許我們平台上的用戶清除他們的帳戶(即刪除他們的所有數據)。 這個例程在一個存儲過程中運行,基本上循環遍歷相關數據表並清除它們創建的所有各種項目。
存儲過程看起來像這樣。
ALTER procedure [dbo].[spDeleteAccountData](
@accountNumber varchar(30) )
AS
BEGIN
SET ANSI_NULLS ON ;
SET NOCOUNT ON;
BEGIN TRAN
BEGIN TRY
DELETE FROM myDataTable1 WHERE accountNumber = @accountNumber
DELETE FROM myDataTable2 WHERE accountNumber = @accountNumber
DELETE FROM myDataTable3 WHERE accountNumber = @accountNumber
//Etc.........
END TRY
BEGIN CATCH
//CATCH ERROR
END CATCH
IF @@TRANCOUNT > 0
COMMIT TRANSACTION;
SET ANSI_NULLS OFF;
SET NOCOUNT OFF;
END
問題是在某些情況下,我們可以在一個表上擁有超過 10,000 行,並且該過程可能需要 3-5 分鍾。 在此期間,數據庫上的所有其他連接都受到限制,導致超時錯誤,如下所示:
System.Data.SqlClient.SqlException (0x80131904):超時已過期。 操作完成前超時時間已過或服務器未響應。
我是否可以進行任何常規更改來提高性能? 我很感激有許多與我們的數據庫架構設計相關的未知數,但歡迎提供一般的最佳實踐建議! 我考慮過將此任務安排在早期運行以最大程度地減少影響,但這遠非理想,因為在此任務完成之前,用戶將無法重新獲得對其帳戶的訪問權限。
附加信息:
編輯:格林威治標准時間 16:52
刪除過程影響大約 20 個表。 最大的一個有大約 500 萬條記錄。 其他的沒有更多的 200,000,有些只包含 1000-2000 條記錄。
所有表中的accountNumber
都有索引嗎?
看到您使用該列的WHERE
子句刪除,這可能會有所幫助。
另一種選擇(可能甚至更好的解決方案)是在晚上安排刪除操作,例如,當用戶選擇刪除他的帳戶時,您只是設置了一個標志,而在晚上運行的刪除作業實際上刪除了那些標記為刪除的帳戶。
如果您在 accountNumber 字段上有索引,那么我想刪除的時間很長是由於鎖定(由其他進程生成)或受相應表影響的外鍵。
當然,純粹主義者會因為后者而責怪我,但在需要時我已經多次使用它。
SqlCommand.CommandTimeout 是簡短的答案。 增加它的價值。
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx
請注意,連接超時與 CommandTimeout 不同。
...
每個表上的“accountNumber”都有索引嗎?
你可以在表的代理鍵上有一個聚集鍵,但不是“accountNumber”。
...
基本上,您將不得不在此處查看執行計划(或發布執行計划)。
但這里有一些“入門代碼”,用於在該列上嘗試索引。
if exists (select * from dbo.sysindexes where name = N'IX_myDataTable1_accountNumber' and id = object_id(N'[dbo].[myDataTable1]'))
DROP INDEX [dbo].[myDataTable1].[IX_myDataTable1_accountNumber]
GO
CREATE INDEX [IX_myDataTable1_accountNumber] ON [dbo].[myDataTable1]([accountNumber])
GO
可能值得將數據庫切換到 Read Committed Snapshot 模式。 這會對性能產生影響,多少取決於您的應用程序。
在 Read Committed Snapshot 模式下,寫入者和讀取者不再相互阻止,盡管寫入者仍然阻止寫入者。 您沒有說明刪除會阻止表上的哪種活動,因此很難說這是否會有所幫助?
http://msdn.microsoft.com/en-us/library/ms188277(v=sql.105).aspx
話雖如此,刪除大約 10k 行的表的 3-5 分鍾似乎慢得荒謬。 你提到外鍵,外鍵有索引嗎? 如果沒有,刪除會導致另一端的表掃描以確保您沒有破壞 RI,所以也許先檢查一下? SQL Server Profiler 對這些刪除查詢的讀/寫有何看法?
您可能想嘗試的一種方法是:
例子:
DECLARE @DeletedRowsCount INT = 1, @BatchSize INT = 300;
WHILE (@DeletedRowsCount> 0) BEGIN
BEGIN TRANSACTION
DELETE TOP (@BatchSize) dbo.Table
FROM dbo.Table
WHERE Id = @PortalId;
SET @DeletedRowsCount = @@ROWCOUNT;
COMMIT;
WAITFOR DELAY '00:00:05';
END
我想你也可以在沒有 SP 的情況下做同樣的事情。 事實上,這樣可能更好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.