2012-01-25 22 views
11

我運行下面的命令來刪除分批行了一大桌(150萬行)的:刪除表中的行事業鎖具

DECLARE @RowCount int 
WHILE 1=1 
    BEGIN 
     DELETE TOP (10000) t1 
     FROM table t1 
     INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey 
     WHERE t1.YearProcessed <= 2007 

     SET @RowCount = @@ROWCOUNT 

     IF (@RowCount < 10000) BREAK 
    END 

此表是使用頻率高的。但是,刪除記錄,但它也造成鎖定在一些記錄,從而引發錯誤給用戶(這是不是在我們的環境中接受)。

我怎麼能不引起鎖刪除舊的記錄?我應該將批量的大小從10000個記錄減少到1000個嗎?這將如何影響日誌大小(我們留下了較大的日誌增長非常小的硬盤空間)。

有什麼建議嗎?

回答

7

我已經看到,即使在小批量0F 5000條記錄而在過去,類似的零星問題,鎖定仍然會發生。在我們的情況下,每個刪除/更新已包含在它自己的begin tran ...提交循環。爲了糾正該問題,

WAITFOR DELAY '00的邏輯:00:00:01'

通過放置在每個循環的頂部和糾正該問題。

+0

這是在每批次或每行刪除的開始/結束? – Sean

4

首先 - 它看起來像你的DELETE執行聚集索引掃描,我建議做到以下幾點:

create index [IX.IndexName] ON t1(YearProcessed, PrimaryKey) 

二 - 有什麼需要加入T2表?

然後用下面的查詢刪除行,假設你的PrimaryKey的列是int類型:

declare @ids TABLE(PrimaryKey INT) 
WHILE 1=1 
    BEGIN 
     INSERT @ids 
     SELECT top 10000 DISTINCT t1.PrimaryKey 
     FROM table t1 
     INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey 
     WHERE t1.YearProcessed <= 2007 

     IF @@ROWCOUNT = 0 BREAK 

     DELETE t1 
     WHERE PrimaryKey in (Select PrimaryKey from @ids) 

     delete from @ids 

    END 

而且不要忘記,如果不需要的話

從加盟刪除T2表如果仍然導致鎖 - 再降低每一輪

+0

我實際上內從父表接合主鍵列表刪除(這實際上是在一個表中的變量)。我只發佈了兩張表來簡化腳本。與你所做的非常相似,但你採取了我將嘗試的另一種方法。 – Sean

0

刪除除了其他建議(即旨在減少刪除的過程中所做的工作)行的量也可以配置SQL Server不阻止其他讀者,而這樣做在上刪除能夠。

這可以通過使用與SQL Server 2005中引入了「快照隔離」來完成:

http://msdn.microsoft.com/en-us/library/ms345124%28v=sql.90%29.aspx

+1

這是很好的注意,快照隔離需要改變單個事務隔離級別。讀取已提交的快照隔離將更改默認隔離級別,但它需要非常短暫的中斷。 –

0

如果您有任何級聯刪除確保它們進行索引。

突出顯示DELETE查詢並單擊Display estimated execution plan將顯示建議的索引 - 在我的情況下包括一些級聯刪除。

那些添加索引進行的刪除速度快了很多 - 但我仍然不會嘗試一次刪除所有行。

0

,我已經找到了最好的辦法是形式asp.net DeleteExpiredSessions。你做了READUNCOMMITTED選擇並把記錄在一個臨時表,比使用遊標刪除的記錄。

ALTER PROCEDURE [dbo].[DeleteExpiredSessions] 
    AS 
     SET NOCOUNT ON 
     SET DEADLOCK_PRIORITY LOW 

     DECLARE @now datetime 
     SET @now = GETUTCDATE() 

     CREATE TABLE #tblExpiredSessions 
     ( 
      SessionID nvarchar(88) NOT NULL PRIMARY KEY 
     ) 

     INSERT #tblExpiredSessions (SessionID) 
      SELECT SessionID 
      FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED) 
      WHERE Expires < @now 

     IF @@ROWCOUNT <> 0 
     BEGIN 
      DECLARE ExpiredSessionCursor CURSOR LOCAL FORWARD_ONLY READ_ONLY 
      FOR SELECT SessionID FROM #tblExpiredSessions 

      DECLARE @SessionID nvarchar(88) 

      OPEN ExpiredSessionCursor 

      FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID 

      WHILE @@FETCH_STATUS = 0 
       BEGIN 
        DELETE FROM [ASPState].dbo.ASPStateTempSessions WHERE SessionID = @SessionID AND Expires < @now 
        FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID 
       END 

      CLOSE ExpiredSessionCursor 

      DEALLOCATE ExpiredSessionCursor 

     END 

     DROP TABLE #tblExpiredSessions 

    RETURN 0 
0

嘗試此,

DECLARE @RowCount int 
WHILE 1=1 
    BEGIN 
     BEGIN TRANSACTION 
     DELETE TOP (10000) t1 
     FROM table t1 
     INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey 
     WHERE t1.YearProcessed <= 2007 
     END TRANSACTION 
     COMMIT TRANSACTION 
     SET @RowCount = @@ROWCOUNT 

     IF (@RowCount < 10000) BREAK 
    END