web-dev-qa-db-ja.com

プリントを使用して時間のかかるストアドプロシージャを追跡する

私はデータベース管理者ではないし、SQL-fooも(まだ)良いものではありませんが、MSSQLで実行するいくつかのタスクがあり、1つはCURSORおよび_WHILE @@FETCH_STATUS = 0_、巨大なテーブルに複数のSELECTsとUPDATEがあります。 (手順は機能します。同僚に確認しました)

スクリプトまたはプログラムで、単純なprint @current_cursorまたはcounterすべてのWHILEsomeフィードバックを得るために。

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.
_
4
Daedalus Mythos

SQL Serverでは(使用している古いバージョンでは機能するはずですが)、通常の方法はRAISERRORを使用することです。 PRINTは、プロセスが終了するまで出力を表示しませんが、あまり役に立ちません。バッチサイズを小さくしたい場所で、更新や削除などのバッチスクリプトでこの手法をよく使用しています。

以下の例では、@Batchsize変数と私のループは一度に多くの行で機能するだけで、それをRAISERRORで出力します。重大度0を使用することが重要です。これは、情報メッセージとしてだけではなく、エラーとして何も処理しないことを意味します。

DECLARE @MsgStr varchar(200) = 'Inserted ' + CAST(@BatchSize AS varchar(10)) + ' rows...'

RAISERROR(@MsgStr, 0, 0) WITH NOWAIT
10
JNK

あなたも行うことができます:

RAISERROR('%d', 0, 0, @cur_id) WITH NOWAIT;

ただし、これらの数に応じて、Management Studioによって提供されるバッファーをオーバーランさせ、出力がすぐに印刷されないシナリオになる可能性があります。

4
Aaron Bertrand

RAISERRORを機能させる方法についての文字通りの質問に対処しようとする気が散ることによって、ここで求められていることの意図が失われているのではないかと思います。 @wBobは素晴らしい質問をしました:「なぜあなたはそれを見ているのですか?」ここでの目的は、プロセスがどこにあるか、プロセスがどこまで進んだかなどを洞察することです。これには、PRINTRAISERRORは必要ありません。

より良いアプローチは、このプロセスを追跡するステータステーブルを作成することです(ただし、公平にするために、@ 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

今:

  • あなたはそれを見る必要はありません:)。
  • SSMSのバッファーがいっぱいになることを心配する必要はなく、メッセージをすぐに報告する必要もありません(@Aaronが言及したことや、私が何度か経験したこと)。
  • ステータスは、画面を見ている人だけでなく、テーブルでSELECTを実行できるすべてのユーザーが利用できます。
  • あなた(または他の誰か)は、実際の監視ソフトウェアを介して監視できます。
  • 適用するWindows Updateがあり、ITが再起動を強制するポリシーを設定しているため、コンピューターが自動的に再起動したときにその履歴が失われることはありません。そのような方針のある場所で働くには?;-).
4
Solomon Rutzky

正直なところ、なぜあなたはそれを見ているのですか?プロシージャに本当に時間がかかる場合は、SQLエージェントジョブを使用して夜間に実行するようにスケジュールを設定し、朝入ったときに実行されるようにします。

長期的には、セットベースのロジックを使用するようにプロシージャをリファクタリングすることを検討してください。これはほぼ確実に高速になるためです。少なくとも、既存のコードがある場合、テストするものがあります。たとえば、上位のボトルネックを特定し、変更を加えます。同じ結果が得られますか?わかりました、もう一度変更してください...

プロシージャが終了するのを待たずに節約された時間を使用して、提供されたリンクの一部を読み、SQLスキルを向上させます。たとえば、SSISを使用して並列処理を行うことができるので、SSISを使用するリファクタリングが役立つかどうかを検討してください。

コードについてさらにサポートが必要な場合は、ここに質問を投稿し、ガイドラインに従ってDDLとサンプルデータを提供してください。誰かがあなたを助けることができると確信しています。

最後に、SQL Serverの古いバージョンとサポート対象外のService Packを使用しています。サービスパックを最新の状態にするか、今年の4月にリリースされたSQL Server 2014にアップグレードすることを検討してください。

幸運を! :)

1
wBob