私はデータベース管理者ではないし、SQL-fooも(まだ)良いものではありませんが、MSSQLで実行するいくつかのタスクがあり、1つはCURSOR
および_WHILE @@FETCH_STATUS = 0
_、巨大なテーブルに複数のSELECT
sとUPDATE
があります。 (手順は機能します。同僚に確認しました)
スクリプトまたはプログラムで、単純なprint @current_cursorまたはcounterすべてのWHILE
でsomeフィードバックを得るために。
MSSQLでこのようなことをするにはどうすればよいですか? (Microsoft SQL Server Enterprise Edition v9.00.3042.00、つまりSQL Server 2005 Service Pack 2で動作)
_print @current_cursor
_を実行することはできますか、それとも私の場合、それはノーゴーですか?
編集
私は以下のステートメントでRAISEERROR
をテストしました:
_DECLARE @cur_id int;
SET @cur_id = 0;
DECLARE Cur CURSOR FOR
SELECT ID FROM TableA
WHERE ID > 100 ORDER BY ID DESC
OPEN Cur
FETCH NEXT FROM Cur INTO @cur_id;
WHILE @@FETCH_STATUS = 0
BEGIN
RAISERROR(@cur_id, 0, 0) WITH NOWAIT
FETCH NEXT FROM Cur INTO @cur_id;
END
_
しかし、これは出力なしでしばらく待機し、それから無限の壁につながります(私はRAISERROR
ごとに1つを想定しています):
_Msg 18054, Level 16, State 1, Line 17
Error 983700, severity 0, state 0 was raised, but no message with that error number was found in sys.messages. If error is larger than 50000, make sure the user-defined message is added using sp_addmessage.
_
SQL Serverでは(使用している古いバージョンでは機能するはずですが)、通常の方法はRAISERROR
を使用することです。 PRINT
は、プロセスが終了するまで出力を表示しませんが、あまり役に立ちません。バッチサイズを小さくしたい場所で、更新や削除などのバッチスクリプトでこの手法をよく使用しています。
以下の例では、@Batchsize
変数と私のループは一度に多くの行で機能するだけで、それをRAISERROR
で出力します。重大度0を使用することが重要です。これは、情報メッセージとしてだけではなく、エラーとして何も処理しないことを意味します。
DECLARE @MsgStr varchar(200) = 'Inserted ' + CAST(@BatchSize AS varchar(10)) + ' rows...'
RAISERROR(@MsgStr, 0, 0) WITH NOWAIT
あなたも行うことができます:
RAISERROR('%d', 0, 0, @cur_id) WITH NOWAIT;
ただし、これらの数に応じて、Management Studioによって提供されるバッファーをオーバーランさせ、出力がすぐに印刷されないシナリオになる可能性があります。
RAISERROR
を機能させる方法についての文字通りの質問に対処しようとする気が散ることによって、ここで求められていることの意図が失われているのではないかと思います。 @wBobは素晴らしい質問をしました:「なぜあなたはそれを見ているのですか?」ここでの目的は、プロセスがどこにあるか、プロセスがどこまで進んだかなどを洞察することです。これには、PRINT
やRAISERROR
は必要ありません。
より良いアプローチは、このプロセスを追跡するステータステーブルを作成することです(ただし、公平にするために、@ wBobの提案には、このプロセスをよりセットベースにリファクタリングするメリットがありますが、状況はわかりません。これをリファクタリングすることは、1つ以上の理由で実行できない場合があります)。そのため、現在のIDのみ(つまり、ステータスのみ)が必要か、それまでに起こったことの実行軌跡(つまり、ログ/履歴)が必要かを検討してください。ログ/履歴テーブルが必要な場合(これは、個々のメッセージを出力するのに最も似ています)、次のようなものを作成します。
ProcessTime DATETIME NOT NULL PRIMARY KEY DEFAULT (GETDATE()),
RowsInserted INT NOT NULL,
CurrentID INT NOT NULL
次に、BEGIN
ループのWHILE
の直後に挿入を行います。
INSERT INTO ProcessLog (RowsInserted, CurrentID) VALUES (@BatchSize, @cur_id);
トランザクション内のループ内でステートメントをグループ化している場合は、このINSERT
が発生することを確認してくださいbeforeBEGIN TRAN
。
今:
正直なところ、なぜあなたはそれを見ているのですか?プロシージャに本当に時間がかかる場合は、SQLエージェントジョブを使用して夜間に実行するようにスケジュールを設定し、朝入ったときに実行されるようにします。
長期的には、セットベースのロジックを使用するようにプロシージャをリファクタリングすることを検討してください。これはほぼ確実に高速になるためです。少なくとも、既存のコードがある場合、テストするものがあります。たとえば、上位のボトルネックを特定し、変更を加えます。同じ結果が得られますか?わかりました、もう一度変更してください...
プロシージャが終了するのを待たずに節約された時間を使用して、提供されたリンクの一部を読み、SQLスキルを向上させます。たとえば、SSISを使用して並列処理を行うことができるので、SSISを使用するリファクタリングが役立つかどうかを検討してください。
コードについてさらにサポートが必要な場合は、ここに質問を投稿し、ガイドラインに従ってDDLとサンプルデータを提供してください。誰かがあなたを助けることができると確信しています。
最後に、SQL Serverの古いバージョンとサポート対象外のService Packを使用しています。サービスパックを最新の状態にするか、今年の4月にリリースされたSQL Server 2014にアップグレードすることを検討してください。
幸運を! :)