SQLエージェントジョブを使用してループでプロシージャを呼び出す
-
05-07-2019 - |
質問
いくつかのデータベーステーブルのレコードをコピーおよび削除するジョブをSQL Enterprise Manager 2000にまとめています。一括コピーを実行し、ストアドプロシージャを削除しましたが、数百万行で実行される可能性があるため、サーバーがハングします。一度に100のようなレコードチャンクでサービスを実行することに興味があったので、サーバーは停止することはありません(これはライブWebデータベースです)。このサービスを1晩に1回実行したいので、エージェントの仕事に入れました。実際にコピーと削除を行ってから「スリープ」するストアドプロシージャの呼び出しをループする方法はありますか?サーバーが追いつくための時間を与えるために各呼び出しの間に? WAITFORコマンドがあることは知っていますが、これがプロセッサを保持するのか、それとも他のクエリを実行するのかはわかりません。
ありがとう!
解決
"チャンク化"削除は、トランザクションログファイルを肥大化させることなく、過剰な量のデータを削除するための好ましい方法です。 BradCの投稿はこの合理的な例です。
このようなループの管理は、単一のストアドプロシージャ内で行うのが最適です。そのような作業を時間をかけて分散させるために、私はそれを手順に残しておきます。ループにWAITFORを挿入すると、「一時停止」が挿入されます。可能性のある同時実行の問題に対処するために必要と判断した場合、各削除セットの間に。 SQLエージェントジョブを使用して、プロシージャが開始するタイミングを決定します。特定の時間までに確実に停止する必要がある場合は、それもループに入れます。
このコードの私のスピンは次のようになります:
-- NOTE: This is a code sample, I have not tested it
CREATE PROCEDURE ArchiveData
@StopBy DateTime
-- Pass in a cutoff time. If it runs this long, the procedure will stop.
AS
DECLARE @LastBatch int
SET @LastBatch = 1
-- Initialized to make sure the loop runs at least once
WHILE @LastBatch > 0
BEGIN
WAITFOR DELAY '00:00:02'
-- Set this to your desired delay factor
DELETE top 1000 -- Or however many per pass are desired
from SourceTable
-- Be sure to add a where clause if you don't want to delete everything!
SET @LastBatch = @@rowcount
IF getdate() > @StopBy
SET @LastBatch = 0
END
RETURN 0
うーん。投稿を読み直すということは、データを削除する前にまずどこかにコピーすることを意味します。これを行うには、一時テーブルを設定し、ループ内で最初に一時テーブルを切り捨ててから、TOP Nアイテムの主キーをコピーして、「アーカイブ」に挿入します。一時テーブルへの結合を介してテーブルを作成してから、一時テーブルへの結合を介してソーステーブルも削除します。 (単純な削除よりも少し複雑ではありませんか?)
他のヒント
ループ間の待機について心配する必要はありません。SQLサーバーは、メンテナンスジョブとサーバー上の通常のアクティビティとの間の競合を処理する必要があります。
この種の状況で実際に問題を引き起こすのは、単一のトランザクション内で削除プロセス全体が一度に発生することです。これはデータベースのログを爆破し、あなたが経験しているように聞こえる種類の問題を引き起こす可能性があります。
次のようなループを使用して、管理可能なチャンクで削除します。
DECLARE @i INT
SET @i = 1
SET ROWCOUNT 10000
WHILE @i > 0
BEGIN
BEGIN TRAN
DELETE TOP 1000 FROM dbo.SuperBigTable
WHERE RowDate < '2009-01-01'
COMMIT
SELECT @i = @@ROWCOUNT
END
SET ROWCOUNT 0
コピーにも同様のロジックを使用できます。
WAITFOR
は、他のプロセスに「許可」を与えます。このテクニックを使用して、大規模なDELETEによるマシンのロックを停止しました。 WHILEループを作成し、行のブロックを削除してから、数秒(またはそれ以下、適切なものは何でも)WAITFORします。