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.