Come svuotare il buffer PRINT in TSQL?


220

Ho una procedura memorizzata di lunga durata in SQL Server 2005 che sto provando a eseguire il debug e sto usando il comando 'print' per farlo. Il problema è che sto solo recuperando i messaggi da SQL Server alla fine del mio sproc: mi piacerebbe poter svuotare il buffer dei messaggi e vedere questi messaggi immediatamente durante il runtime dello sproc, piuttosto che fine.


1
Solo un breve preavviso per le persone che (come me) penseranno che le risposte non funzionino per loro: assicurati di passare alla scheda "Messaggi" quando la query è in esecuzione. Per impostazione predefinita, vedrai la scheda "Risultati".
Tomasz Gandor,

Risposte:


305

Usa la RAISERRORfunzione:

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

Non dovresti sostituire completamente tutte le tue stampe con raiserror. Se hai un loop o un cursore grande da qualche parte, fallo una o due volte per ogni iterazione o anche solo per diverse iterazioni.

Inoltre: ho appreso per la prima volta di RAISERROR a questo link, che ora considero l'origine definitiva sulla gestione degli errori di SQL Server e merita sicuramente una lettura:
http://www.sommarskog.se/error-handling-I.html


41
Si noti che TRY / CATCH in SQL rileverà solo errori con gravità> 10, quindi l'utilizzo di RAISERROR in questo modo non passerà all'istruzione CATCH. È fantastico, poiché significa che puoi ancora usare RAISERROR in questo modo con TRY / CATCH. rif: msdn.microsoft.com/en-us/library/ms175976.aspx
Rory

13
Si noti che questo non funziona dopo i primi 500 messaggi; una volta stampato più di questo, inizia improvvisamente il buffering!
GendoIkari,

@MahmoudMoravej No, sto ancora eseguendo processi a lungo termine con RAISEERROR, e sto solo affrontando il fatto che dopo un po 'i messaggi iniziano a essere bufferizzati. Sembra che l'unica soluzione sarebbe quella di utilizzare uno strumento diverso da SSMS.
GendoIkari,

1
Penso che questo sia qualcosa che è cambiato in una recente versione di SS. Molto tempo fa, quando l'ho scritto per la prima volta, abbiamo usato RAISERROR per la registrazione estesa di processi batch durante la notte con molti più di 500 messaggi, e non è stato un problema. Ma molto può cambiare in 7 anni.
Joel Coehoorn,

1
All'avviso di @ GendoIkari. L'ho provato con SMS da 2016SP1 con questo script. A 500 passa al buffering di 50 righe e a 1k passa a 100 righe ciascuna. Questo è continuato almeno fino a 2k, ma poi ho interrotto la sceneggiatura. declare @i int set @i = 0 declare @t varchar (100) mentre 1 = 1 inizia set @i = @i + 1 set @t = 'print' + convert (varchar, @i) RAISERROR (@t, 10 , 1) CON NOWAIT waitfor delay '00: 00: 00.010 'end
Zartag

28

Basandomi sulla risposta di @JoelCoehoorn, il mio approccio è quello di lasciare tutte le mie dichiarazioni PRINT sul posto e semplicemente seguirle con l'istruzione RAISERROR per causare il flush.

Per esempio:

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

Il vantaggio di questo approccio è che le istruzioni PRINT possono concatenare le stringhe, mentre RAISERROR no. (Quindi in entrambi i casi hai lo stesso numero di righe di codice, come dovresti dichiarare e impostare una variabile da usare in RAISERROR).

Se, come me, usi AutoHotKey o SSMSBoost o uno strumento equivalente, puoi facilmente impostare un collegamento come "] flush" per inserire la riga RAISERROR per te. Ciò consente di risparmiare tempo se si tratta sempre della stessa riga di codice, ovvero non è necessario personalizzarlo per contenere testo specifico o una variabile.


6
Nota che RAISERROR()supporta l' printf()interpolazione di stringhe in stile. Ad esempio, se @MyVariableNameè un tipo stringish (ad esempio, VARCHAR(MAX), NVARCHAR(MAX)e così via), è possibile utilizzare RAISERROR()con una sola riga: RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName).
binki,

Questo è così conveniente! So che RAISERROR può fare una semplice sostituzione, ma prova a sostituire un'ora [data] o a chiamare una funzione dall'interno dell'istruzione RAISERROR! Questa risposta ti dà un semplice FLUSH sotto forma di errore vuoto (al costo di una nuova riga).
Tomasz Gandor,

19

Sì ... Il primo parametro della funzione RAISERROR richiede una variabile NVARCHAR. Quindi prova quanto segue;

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

O

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

10
Guarda la scheda Messaggi in basso, accanto alla scheda Risultati o passa alla modalità Risultati in Testo.
Mehmet Ergut,

Per passare alla modalità Risultati in modalità Testo, in SSMS, menu Strumenti -> Opzioni -> Risultati query -> SQL Server -> Generale -> Destinazione predefinita per i risultati e scegliere "Risultati in testo" anziché "Risultati in griglie", ri -apri la finestra della query e poi non ti siederai lì guardando una scheda Risultati vuota come un manichino mentre l'output di RAISERROR passa alla scheda Messaggi.
Adam,

12

Un'altra opzione migliore è quella di non dipendere da PRINT o RAISERROR e caricare semplicemente le istruzioni "print" in una tabella ## Temp in TempDB o una tabella permanente nel database che ti darà immediatamente visibilità ai dati tramite un'istruzione SELECT da un'altra finestra . Questo funziona meglio per me. L'uso di una tabella permanente funge anche da registro per ciò che è accaduto in passato. Le istruzioni di stampa sono utili per gli errori, ma utilizzando la tabella dei registri è anche possibile determinare il punto esatto dell'errore in base all'ultimo valore registrato per quella particolare esecuzione (presupponendo che si tenga traccia dell'orario di inizio complessivo dell'esecuzione nella tabella dei registri).


2
Questo potrebbe essere un problema se stai scrivendo uno script veramente transazionale con commit e rollback. Non credo che sarai in grado di interrogare la tua tabella temporanea in tempo reale e andrà via se la tua transazione fallisce.
SteveJ,

@SteveJ puoi interrogarlo dal vivo usando SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;nella tua sessione di monitoraggio
TheConstructor il

1
@TheConstructor; Questo è un consiglio utile - lo userò, grazie. Tuttavia, non siamo ancora rimasti con la tabella temporanea andando via al rollback? Se si esegue l'analisi degli errori, sembra che sarebbe un grosso difetto.
SteveJ,

1
@SteveJ sì, c'è sicuramente questo. Ovviamente puoi copiare i dati di una READ UNCOMMITTEDtransazione su un'altra tabella, ma probabilmente ti perdi il momento prima ROLLBACK. Quindi probabilmente risolve il "quanto lontano?" non il "perché rollback?"
TheConstructor il

4

Solo per riferimento, se si lavora in script (elaborazione batch), non in stored procedure , l'output di flushing viene attivato dal comando GO, ad es.

print 'test'
print 'test'
go

In generale, la mia conclusione è la seguente: l'output dell'esecuzione dello script mssql, eseguito nella GUI di SMS o con sqlcmd.exe, viene scaricato nel file, stdoutput, finestra della GUI sulla prima istruzione GO o fino alla fine dello script.

Il lavaggio all'interno delle procedure memorizzate funziona in modo diverso, poiché non è possibile posizionare GO all'interno.

Riferimento: istruzione tsql Go


2
gonon solo scarica l'output, ma termina il batch secondo il collegamento fornito. Tutto ciò che declareviene scartato, quindi non molto utilizzabile per il debug. declare @test int print "I want to read this!" go set @test=5sarà comunque un errore affermando che @testnon è definito perché è in un nuovo batch.
asontu,

1
Sono d'accordo, questa non è una risposta adeguata a questa domanda, ma ho inserito la risposta (vedere la dichiarazione di non responsabilità all'inizio) poiché potrebbe essere utile per qualcun altro, ad esempio qualcuno che esegue batch sql.
Robert Lujo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.