簡體   English   中英

SQL Server 刪除性能

[英]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):超時已過期。 操作完成前超時時間已過或服務器未響應。

我是否可以進行任何常規更改來提高性能? 我很感激有許多與我們的數據庫架構設計相關的未知數,但歡迎提供一般的最佳實踐建議! 我考慮過將此任務安排在早期運行以最大程度地減少影響,但這遠非理想,因為在此任務完成之前,用戶將無法重新獲得對其帳戶的訪問權限。

附加信息:

  • SQL Server 2008 R2 標准版
  • 所有表都有聚集索引
  • 沒有觸發器與任何相關表上的任何刪除命令相關聯
  • 許多表上都存在外鍵引用,但刪除順序對此進行了說明。

編輯:格林威治標准時間 16:52

刪除過程影響大約 20 個表。 最大的一個有大約 500 萬條記錄。 其他的沒有更多的 200,000,有些只包含 1000-2000 條記錄。

所有表中的accountNumber都有索引嗎?

看到您使用該列的WHERE子句刪除,這可能會有所幫助。

另一種選擇(可能甚至更好的解決方案)是在晚上安排刪除操作,例如,當用戶選擇刪除他的帳戶時,您只是設置了一個標志,而在晚上運行的刪除作業實際上刪除了那些標記為刪除的帳戶。

如果您在 accountNumber 字段上有索引,那么我想刪除的時間很長是由於鎖定(由其他進程生成)或受相應表影響的外鍵。

  1. 如果是由於鎖,那么您應該看看是否可以使用 nolock 減少它們,而實際上您可以這樣做。
  2. 如果存在外鍵問題 .. 好吧,您必須等待 .. 如果您不想等待並且您的應用程序邏輯不依賴於強制執行 FK(例如向應用程序發送 FK 違規的錯誤,並針對 FK 進行測試)他們)或者你覺得你的應用程序是完美的,然后在短時間內你不需要 FK,那么你可以在刪除之前禁用相關的 FK,然后使用 ALTER TABLE xxx NOCHECK CONSTRAINT all 然后重新啟用它。

當然,純粹主義者會因為后者而責怪我,但在需要時我已經多次使用它。

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 對這些刪除查詢的讀/寫有何看法?

您可能想嘗試的一種方法是:

  1. 創建一個 SP。
  2. 對於每個表,以適合您的大小小批量刪除行(例如每批 10 行)。
  3. 將每個批量刪除放在一個事務中,並在每個事務之間添加自定義延遲。

例子:

    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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM