TSQL에서 PRINT 버퍼를 어떻게 플러시합니까?


220

SQL Server 2005에서 디버깅하려고하는 매우 오래 실행되는 저장 프로 시저가 있으며 'print'명령을 사용하여 수행하고 있습니다. 문제는 sproc의 맨 마지막에 SQL Server에서 메시지를 다시 가져 오는 것입니다. 메시지 버퍼를 플러시하고 sproc의 런타임 중에 메시지 버퍼를 플러시하고 즉시 볼 수 있기를 바랍니다. 종료.


1
답이 효과가 없다고 생각하는 사람들에게는 짧은 알림 만 있습니다. 쿼리가 실행될 때 "메시지"탭으로 전환하십시오. 기본적으로 "결과"탭이 표시됩니다.
Tomasz Gandor

답변:


305

RAISERROR기능을 사용하십시오 :

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

모든 지문을 raiserror로 완전히 교체해서는 안됩니다. 루프 또는 큰 커서가 어딘가에 있으면 반복마다 한 번 또는 두 번 또는 심지어 여러 번 반복하십시오.

또한 :이 링크에서 RAISERROR에 대해 처음 알게되었습니다.이 링크는 이제 SQL Server 오류 처리에 대한 결정적인 소스를 고려하고 읽을 가치가 있습니다 .http :
//www.sommarskog.se/error-handling-I.html


41
SQL의 TRY / CATCH는 심각도가 10보다 큰 오류 만 포착하므로 RAISERROR를 사용하면 CATCH 문으로 이동하지 않습니다. TRY / CATCH에서 이와 같이 RAISERROR를 계속 사용할 수 있다는 것을 의미합니다. 참조 : msdn.microsoft.com/en-us/library/ms175976.aspx
Rory

13
처음 500 개 메시지 이후에는 작동하지 않습니다. 그 이상 인쇄하면 갑자기 버퍼링이 시작됩니다!
GendoIkari

@MahmoudMoravej 아니요, RAISEERROR를 사용하여 장기 실행 프로세스를 계속 실행 중이며 잠시 후 메시지가 버퍼링되기 시작한다는 사실을 처리합니다. SSMS 이외의 다른 도구를 사용하는 것이 유일한 해결책 인 것 같습니다.
GendoIkari

1
나는 이것이 SS의 최신 버전에서 변경된 것이라고 생각합니다. 처음에 이것을 썼을 때 우리는 500 개가 넘는 메시지로 밤새 배치 프로세스를 광범위하게 로깅하기 위해 RAISERROR를 사용했지만 문제가되지 않았습니다. 그러나 7 년 안에 많은 것이 변할 수 있습니다.
Joel Coehoorn

1
@GendoIkari의 통지에서. 이 스크립트를 사용하여 2016SP1의 ssms로 시도했습니다. 500에서 50 개의 버퍼링 라인으로 전환하고 1k에서 각각 100 개의 라인으로 전환합니다. 이것은 적어도 2k까지 계속되었지만 스크립트를 중단했습니다. @i int set @i = 0 선언 @t varchar (100) 선언 1 = 1 시작 설정 @i = @i + 1 set @t = 'print'+ convert (varchar, @i) RAISERROR (@t, 10 , 1) WITH NOWAIT 대기 시간 지연 '00 : 00 : 00.010 '종료
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(): 하나 개의 라인은 RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName).
binki

이것은 매우 편리합니다! RAISERROR가 간단한 대체 작업을 수행 할 수 있지만 [날짜] 시간을 대체하거나 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
하단의 결과 탭 옆에있는 메시지 탭을 보거나 결과를 텍스트로 모드로 전환하십시오.
메멧 에르 구트

SSMS에서 결과를 텍스트 모드로 전환하려면 메뉴 도구-> 옵션-> 쿼리 결과-> SQL Server-> 일반-> 결과에 대한 기본 대상을 선택하고 "결과를 그리드로"대신 "텍스트로 결과"를 선택하십시오. -쿼리 창을 열면 RAISERROR 출력이 메시지 탭으로 이동하는 동안 더미와 같은 빈 결과 탭을보고 앉아 있지 않습니다.
아담

12

PRINT 또는 RAISERROR에 의존하지 않고 "print"문을 TempDB의 ## Temp 테이블 또는 데이터베이스의 영구 테이블에로드하면 다른 창에서 SELECT 문을 통해 즉시 데이터를 볼 수 있습니다. . 이것은 나에게 가장 효과적입니다. 영구 테이블을 사용하면 과거에 발생한 일에 대한 로그 역할도합니다. print 문은 오류에 유용하지만 로그 테이블을 사용하면 해당 특정 실행에 대해 마지막으로 기록 된 값을 기반으로 정확한 실패 지점을 확인할 수도 있습니다 (로그 테이블에서 전체 실행 시작 시간을 추적한다고 가정).


2
커밋 및 롤백을 사용하여 진정한 트랜잭션 스크립트를 작성하는 경우 문제가 될 수 있습니다. 임시 테이블을 실시간으로 쿼리 할 수 ​​있다고 생각하지 않으며 거래가 실패하면 사라질 것입니다.
SteveJ

@SteveJ 당신은 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;모니터링 세션에서 사용하여 라이브 쿼리 할 수 ​​있습니다
TheConstructor

1
@TheConstructor; 도움이 될만한 팁입니다. 감사합니다. 그러나 여전히 임시 테이블을 롤백 할 때 떠나지 않습니까? 실패 분석을 수행하면 큰 단점이 될 것 같습니다.
SteveJ

1
@SteveJ 예, 확실히 있습니다. 물론 READ UNCOMMITTED트랜잭션 의 데이터 를 다른 테이블 에 복사 할 수도 있지만 직전의 순간을 놓칠 수도 ROLLBACK있습니다. 그래서 아마도 '얼마나 멀리?' 왜 롤백이 아닌가?
The Constructor

4

참고로, 스토어드 프로 시저가 아닌 스크립트 (일괄 처리)에서 작업하는 경우 플러싱 출력이 GO 명령에 의해 트리거됩니다 (예 :

print 'test'
print 'test'
go

일반적으로 내 결론은 다음과 같습니다. SMS GUI 또는 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

1
나는 이것이이 질문에 대한 올바른 대답은 아니지만 동의를 얻었습니다 (처음에 면책 조항 참조).
Robert Lujo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.