Published on

December 20, 2022

Улучшение отслеживания прогресса кода в SQL Server

При работе с T-SQL скриптами и хранимыми процедурами в SQL Server может быть сложно получить мгновенное представление о прогрессе кода. По умолчанию, операторы PRINT и вывод RAISERROR не отображаются до завершения процедуры. Однако, существует решение этой проблемы, которое позволяет получать немедленную обратную связь о прогрессе кода.

Решение заключается в использовании оператора RAISERROR с ключевым словом WITH NOWAIT. Удивительно, но для использования оператора RAISERROR не требуется наличие ошибки. Если уровень серьезности, указанный для оператора RAISERROR, находится в диапазоне от 0 до 10, SQL Server рассматривает его как обычное сообщение, а не ошибку. Выполнение продолжается с следующего оператора, даже если есть блок TRY/CATCH или если установлено значение SET XACT_ABORT ON. Сочетая уровень серьезности RAISERROR от 0 до 10 с ключевым словом WITH NOWAIT, вы можете мгновенно отправлять вывод в окно сообщений.

Вот пример использования оператора RAISERROR с ключевым словом WITH NOWAIT:

RAISERROR ('Вот это я называю сообщением!', 0, 1) WITH NOWAIT

Используя этот подход, вы можете получать обновления о прогрессе кода в режиме реального времени, не дожидаясь завершения процедуры.

Важно отметить, что при отправке результатов запроса в сетку, окно сообщений может быть скрыто. Для решения этой проблемы вы можете либо отправить результаты в текст, используя меню или CTRL+T, либо щелкнуть по окну сообщений или использовать команду меню SSMS Window/Next Pane для отображения сообщений.

Вот пример скрипта, демонстрирующего использование операторов PRINT и RAISERROR с ключевым словом WITH NOWAIT:

DECLARE @time char(8)
PRINT '1 PRINT перед всем остальным      ' 
        + convert (varchar(30), getdate(), 8)
SET @time= convert (varchar(30), getdate(), 8)
RAISERROR ('2 RAISERROR перед WITHOUT NOWAIT %s', 0, 1, @time) 
WAITFOR DELAY '00:00:05'
PRINT '3 PRINT после первой задержки     ' 
         + convert (varchar(30), getdate(), 8)
SET @time= convert (varchar(30), getdate(), 8)
RAISERROR ('4 RAISERROR с NOWAIT           %s', 0, 1, @time) 
    WITH NOWAIT
WAITFOR DELAY '00:00:10'
PRINT '5 PRINT после второй задержки    ' 
                 + convert (varchar(30), getdate(), 8)

Выполнив этот скрипт, вы увидите результаты в окне сообщений в режиме реального времени, с каждым сообщением, появляющимся сразу после его выполнения.

Чтобы использование ключевого слова WITH NOWAIT было более удобным, вы можете создать простую хранимую процедуру, которая включает оператор RAISERROR с ключевым словом WITH NOWAIT. Эту хранимую процедуру можно выполнять всякий раз, когда вам нужно отправить немедленное сообщение вызывающей стороне.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE proc [dbo].[ns_log_nowait]  
   @Msg nvarchar(2047)
AS
    RAISERROR (@Msg, 0, 1) WITH NOWAIT 
GO 
GRANT EXECUTE on [dbo].[ns_log_nowait] to PUBLIC
GO

Используя эту хранимую процедуру, вы можете легко отправлять немедленные сообщения вызывающей стороне, не включая вручную оператор RAISERROR с ключевым словом WITH NOWAIT каждый раз.

Важно отметить, что оператор RAISERROR с уровнем серьезности менее 11 не рассматривается как ошибка в конструкции TRY/CATCH, и ключевое слово NOWAIT не влияет на это поведение. Однако, оператор RAISERROR с уровнем серьезности 0 рассматривается как оператор PRINT. Вот пример скрипта, демонстрирующего это поведение:

DECLARE @time char(8)
BEGIN TRY
    PRINT '1 PRINT в блоке TRY ' 
            + convert (varchar(30), getdate(), 8)
    SET @time= convert (varchar(30), getdate(), 8)
    RAISERROR ('2 RAISERROR с NOWAIT %s', 0, 1, @time) WITH NOWAIT
    WAITFOR DELAY '00:00:05'
END TRY 
BEGIN CATCH
    PRINT '3 PRINT в блоке CATCH ' 
         + convert (varchar(30), getdate(), 8)
    PRINT '3A Номер ошибки = ' +convert (VARCHAR, ERROR_NUMBER())
        + ' Серьезность = ' + convert (varchar, ERROR_SEVERITY())
        + ' Сообщение = ''' + ERROR_MESSAGE() + ''''
END CATCH 
PRINT '4 PRINT после блока CATCH ' 
+ convert (varchar(30), getdate(), 8)

Выполнив этот скрипт, вы увидите, что оператор RAISERROR в блоке TRY рассматривается как оператор PRINT и не вызывает блок CATCH. Однако, если вы измените уровень серьезности оператора RAISERROR на 11, он будет рассматриваться как ошибка и вызовет блок CATCH.

Стоит отметить, что использование ключевого слова WITH NOWAIT работает в SQL Server 2000, 2005 и 2008, обеспечивая последовательное поведение в разных версиях SQL Server.

Используя ключевое слово WITH NOWAIT оператора RAISERROR, вы можете улучшить представление о прогрессе вашего кода в SQL Server. Это позволяет получать обновления и сообщения в режиме реального времени, что упрощает отладку и мониторинг ваших скриптов и хранимых процедур.

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.