TSQLでPRINTバッファをフラッシュする方法を教えてください。


220

SQL Server 2005に非常に長時間実行されるストアドプロシージャがあり、これをデバッグしようとしています。そのために 'print'コマンドを使用しています。問題は、sprocの最後にのみSQL Serverからメッセージを取得していることです。メッセージバッファーをフラッシュして、sprocのランタイム中にではなく、sprocの実行中にこれらのメッセージをすぐに確認できるようにしたいのです。終わり。


1
(私のように)回答が役に立たないと思う人のためのちょっとした通知です。クエリが実行されているときは、必ず[メッセージ]タブに切り替えてください。デフォルトでは、[結果]タブが表示されます。
Tomasz Gandor

回答:


305

RAISERROR関数を使用します。

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT

すべてのプリントをレイサーで完全に置き換えることはできません。どこかにループまたは大きなカーソルがある場合は、反復ごとに1回または2回、あるいは数回の反復ごとに実行してください。

また、私はこのリンクでRAISERRORについて最初に学びました。このリンクは、SQL Serverのエラー処理に関する決定的な情報源と考えており、間違いなく読む価値があります。http
//www.sommarskog.se/error-handling-I.html


41
SQLのTRY / CATCHは重大度> 10のエラーのみをキャッチするため、この方法でRAISERRORを使用してもCATCHステートメントにジャンプしないことに注意してください。これは、このようなRAISERRORをTRY / CATCHで引き続き使用できることを意味するので、すばらしいことです。ref:msdn.microsoft.com/en-us/library/ms175976.aspx
Rory

13
これは最初の500メッセージの後では機能しないことに注意してください。それ以上印刷すると、突然バッファリングが始まります!
げんどいかり

@MahmoudMoravejいいえ、私はまだRAISEERRORを使用して実行時間の長いプロセスを実行しており、しばらくするとメッセージがバッファリングされ始めるという事実に対処しています。唯一の解決策は、SSMS以外の別のツールを使用することです。
玄道いかり

1
これは、SSの最近のバージョンで変更されたものだと思います。私が最初にこれを書いたとき、私たちはRAISERRORを使用して、500を超えるメッセージを含む夜間バッチプロセスの広範なロギングを行っていましたが、問題はありませんでした。しかし、7年間で多くのことが変わる可能性があります。
Joel Coehoorn、2015年

1
@GendoIkariの通知。このスクリプトを使用して、2016SP1のssmsで試してみました。500で50行のバッファリングに切り替わり、1kでそれぞれ100行に切り替わります。これは少なくとも2kまで続きましたが、その後スクリプトを停止しました。declare @i int set @i = 0 declare @t varchar(100)while 1 = 1 begin set @i = @i + 1 set @t = 'print' + convert(varchar、@i)RAISERROR(@t、10 、1)NOWAIT waitfor delay '00:00:00.010 'end
Zartag

28

@JoelCoehoornの回答に基づいて、私のアプローチは、すべてのPRINTステートメントをそのままにして、それらの後にRAISERRORステートメントを実行するだけでフラッシュを実行することです。

例えば:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT

このアプローチの利点は、PRINTステートメントが文字列を連結できるのに対して、RAISERRORはできないことです。(つまり、RAISERRORで使用する変数を宣言して設定する必要があるため、どちらの方法でも同じ行数のコードを使用できます)。

私のように、AutoHotKey、SSMSBoost、または同等のツールを使用している場合は、 "] flush"などのショートカットを簡単に設定して、RAISERROR行を入力できます。毎回同じコード行である場合、つまり特定のテキストや変数を保持するためにカスタマイズする必要がない場合、これにより時間を節約できます。


6
RAISERROR()は- printf()形式の文字列補間をサポートしています。例えば、場合@MyVariableNamestringishタイプ(例えば、あるVARCHAR(MAX)NVARCHAR(MAX)など)は、使用することができますRAISERROR()1行で:RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName)
binki 2018

これはとても便利です!私はRAISERRORがいくつかの単純な置換を実行できることを知っていますが、[date] timeを置換するか、RAISERRORステートメント内から関数を呼び出してみてください!この答えは、(改行を犠牲にして)空のエラーを発生させる形で単純なFLUSHを提供します。
Tomasz Gandor

19

はい... RAISERROR関数の最初のパラメーターには、NVARCHAR変数が必要です。したがって、以下を試してください。

-- Replace PRINT function
DECLARE @strMsg NVARCHAR(100)
SELECT @strMsg = 'Here''s your message...'
RAISERROR (@strMsg, 0, 1) WITH NOWAIT

または

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT

10
下部の[結果]タブの横にある[メッセージ]タブを確認するか、[結果からテキスト]モードに切り替えます。
Mehmet Ergut、2011年

結果をテキストモードに切り替えるには、SSMSで、[ツール]-> [オプション]-> [クエリ結果]-> [SQL Server]-> [全般]-> [結果のデフォルトの出力先]を選択し、[グリッドの結果]ではなく[テキストの結果]を選択します。 -クエリウィンドウを開くと、RAISERRORの出力が[メッセージ]タブに移動する間、ダミーのように空の[結果]タブを見ていることはありません。
アダム

12

別のより良いオプションは、PRINTやRAISERRORに依存せず、「print」ステートメントをTempDBの## Tempテーブルまたはデータベースの永続テーブルにロードすることです。これにより、別のウィンドウからSELECTステートメントを介してデータを即座に表示できます。 。これは私にとって最も効果的です。永続的なテーブルを使用すると、過去に何が起こったかのログとしても機能します。印刷ステートメントはエラーの場合に便利ですが、ログテーブルを使用すると、その特定の実行について最後にログに記録された値に基づいて、障害の正確なポイントを特定することもできます(ログテーブルで全体の実行開始時間を追跡するとします)。


2
コミットとロールバックを備えた真のトランザクションスクリプトを記述している場合、これは問題になる可能性があります。一時テーブルをライブでクエリできるようになるとは思いません。トランザクションが失敗すると、一時テーブルはなくなります。
SteveJ

@SteveJ SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;監視セッションで使用することで、ライブでクエリを実行できます
TheConstructor

1
@TheConstructor; これは役立つヒントです。ありがとうございます。ただし、ロールバック時に一時テーブルがなくなるのではないですか?障害分析を行う場合、それは大きな欠点になるようです。
SteveJ

1
@SteveJはい、確かにこれがあります。もちろん、READ UNCOMMITTEDトランザクション内のデータを別のテーブルにコピーすることもできますが、直前の瞬間を見逃している可能性がありますROLLBACK。したがって、おそらく「どこまで」を解決するでしょう。「ロールバックする理由」ではありません
TheConstructor 2016

4

参考までに、ストアドプロシージャはなくスクリプト(バッチ処理)で作業している場合、出力のフラッシュはGOコマンドによってトリガーされます

print 'test'
print 'test'
go

一般的に、私の結論は次のとおりです。SMSGUIまたはsqlcmd.exeで実行されるmssqlスクリプト実行の出力は、最初のGOステートメントで、またはスクリプトの終わりまで、ファイル、stdoutput、guiウィンドウにフラッシュされます。

ストアドプロシージャ内のフラッシュは、GOを内部に配置できないため、機能が異なります。

リファレンス:tsql Goステートメント


2
go出力をフラッシュするだけでなく、指定したリンクに従ってバッチを終了します。あなたが何かdeclareDは、デバッグのためのとても使用できない、破棄されます。declare @test int print "I want to read this!" go set @test=5ただし@test、新しいバッチに含まれているため、未定義のエラーは未定義です。
asontu 2015

1
私は同意します。これはこの質問に対する適切な回答ではありませんが、他の誰か(たとえば、バッチSQLを実行する人)に役立つ可能性があるので、回答(冒頭の免責事項を参照)を示します。
Robert Lujo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.