SQL Server 2005を使用します。
where句のない巨大なDELETE FROMを実行しています。基本的にTRUNCATE TABLEステートメントと同等です-TRUNCATEの使用が許可されていないことを除きます。問題は、テーブルが巨大である-1000万行であり、完了するまでに1時間以上かかることです。以下なしで高速化する方法はありますか?
- 切り捨ての使用
- インデックスを無効化または削除しますか?
t-logはすでに別のディスクにあります。
どんな提案も歓迎します!
SQL Server 2005を使用します。
where句のない巨大なDELETE FROMを実行しています。基本的にTRUNCATE TABLEステートメントと同等です-TRUNCATEの使用が許可されていないことを除きます。問題は、テーブルが巨大である-1000万行であり、完了するまでに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を使用できない場合、削除を管理可能なチャンクにバッチ処理する提案に同意し、独創性のためのドロップ/作成の提案が好きですが、質問の次のコメントに興味があります:
基本的にTRUNCATE TABLEステートメントと同等です - ただし、TRUNCATEの使用は許可されていません
この制限の理由は、テーブルを直接切り捨てるために付与する必要があるセキュリティと、関係するテーブル以外のテーブルを切り捨てることができるという事実に関係していると推測しています。
その場合、TRUNCATE TABLEを使用し、 "EXECUTE AS"を使用するストアドプロシージャを作成することは、テーブルを直接切り捨てるのに必要なセキュリティ権限を与えるための実行可能な代替手段と考えられますか。
願わくば、これで必要な速度が得られると同時に、アカウントをdb_ddladminロールに追加することで会社が抱えるセキュリティ上の懸念に対処できます。
この方法でストアドプロシージャを使用する別の利点は、特定のアカウントのみが使用できるようにストアドプロシージャ自体をロックダウンできることです。
何らかの理由でこれが許容できる解決策ではなく、このテーブルのデータを削除する必要がある場合は、1日1時間ごとなどに実行する必要がある場合は、テーブルを切り捨てるSQLエージェントジョブを作成するように要求します毎日予定された時間に。
お役に立てれば!
truncateを除く..バッチでの削除のみが役立ちます。
もちろん、すべての制約とインデックスを使用して、テーブルを削除して再作成できます。Management Studioには、ドロップして作成するテーブルをスクリプト化するオプションがあるため、簡単なオプションになります。ただし、これは、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;