条項なしでからの巨大な削除をスピードアップする方法

dba.stackexchange https://dba.stackexchange.com/questions/1750

  •  16-10-2019
  •  | 
  •  

質問

SQL Server 2005の使用。

私は、条項なしで大きな削除を実行しています。基本的には、切り捨てられたテーブルステートメントに相当します - トランケートを使用することは許可されていないことを除きます。問題は、テーブルが巨大であり、1,000万列で、完了するまでに1時間以上かかります。なしでそれをより速くする方法はありますか:

  • トランケートを使用します
  • インデックスの無効化またはドロップ?

T-Logはすでに別のディスク上にあります。

どんな提案も大歓迎です!

役に立ちましたか?

解決

あなたができることは、このようなバッチ削除です:

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable

XXXは、たとえば50000です

非常に高い割合の行を削除したい場合、これを変更します...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable

他のヒント

TOP句を使用してこれを簡単に行うことができます。

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END

あなたがトランケートを使用できない場合、あなたの削除を管理可能なチャンクにバッチバッチするという提案に同意します、そして、私はそれが独創性のためにドロップ/作成された提案が好きですが、私はあなたの質問の次のコメントに興味があります:

それは基本的に切り捨てられたテーブルステートメントに相当します - 私が切り捨てを使用することは許可されていないことを除いて

この制限の理由は、テーブルを直接切り捨てるために付与される必要があるセキュリティと、それがあなたが関心のあるもの以外のテーブルを切り捨てることができるという事実に関係していると推測しています。

それが事実であると仮定すると、Truncateテーブルを使用し、「実行」を使用するストアドプロシージャを作成して、テーブルを直接切り捨てるために必要なセキュリティ権を与えるための実行可能な代替手段と見なされるかどうか疑問に思っています。

うまくいけば、これにより、必要な速度が得られると同時に、DB_DDLADMINの役割にアカウントを追加することで会社が抱えているセキュリティの懸念に対処します。

この方法でストアドプロシージャを使用するもう1つの利点は、特定のアカウントのみが使用できるように、ストアドプロシージャ自体をロックダウンできることです。

何らかの理由でこれが許容可能なソリューションではなく、この表にデータを削除する必要がある場合、1日/時間/時間などを行う必要がある場合、テーブルを切り捨てるためにSQLエージェントジョブが作成されたことを要求します。毎日予定されている時間に。

お役に立てれば!

トランケートを除いて..バッチ内の削除のみが役立ちます。

テーブルをドロップして、すべての制約とインデックスを使用して、コースを再現できます。管理スタジオでは、ドロップして作成するテーブルをスクリプト化するオプションがあるため、些細なオプションである必要があります。しかし、これはDDLアクションを実行することを許可されている場合にのみ、実際には選択肢ではないと思います。

この質問は非常に重要なリファレンスであるため、このコードを投稿しているので、ループを使用して削除し、ループ内でのメッセージングを理解して進行状況を追跡するのにも役立ちました。

クエリはから変更されます これ 重複した質問。のクレジット @RLF クエリベース用。

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME 
DECLARE @currenttime DATETIME 

SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0  -- Total rows deleted so far is 0
SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()

WHILE @RowsTouched > 0
BEGIN
   DELETE TOP (@HowMany)
   FROM #DelTest 
   WHERE name LIKE '%sys%';

   SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
   SET @TotalRowCount = @TotalRowCount+@RowsTouched; -- Increment Total rows deleted count
   SET @currenttime = GETDATE();
   SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
   RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;
ライセンス: CC-BY-SA帰属
所属していません dba.stackexchange
scroll top