У меня есть очень долго выполняющаяся хранимая процедура в SQL Server 2005, которую я пытаюсь отлаживать, и для этого я использую команду print. Проблема в том, что я получаю сообщения от SQL Server только в самом конце моего sproc - я хотел бы иметь возможность очистить буфер сообщений и сразу увидеть эти сообщения во время выполнения sproc, а не в самом конце конец.





Используйте функцию 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
Обратите внимание, что TRY / CATCH в SQL будет отлавливать только ошибки с серьезностью> 10, поэтому использование RAISERROR таким образом не перейдет в ваш оператор CATCH. И это здорово, так как это означает, что вы все еще можете использовать RAISERROR таким образом с TRY / CATCH. ссылка: msdn.microsoft.com/en-us/library/ms175976.aspx
Обратите внимание, что это не работает после первых 500 сообщений; как только вы печатаете больше, он внезапно начинает буферизоваться!
@MahmoudMoravej Нет, я все еще запускаю длительные процессы, используя RAISEERROR, и просто имею дело с тем фактом, что через некоторое время сообщения начинают буферизоваться. Похоже, единственное решение - использовать другой инструмент, отличный от SSMS.
Я думаю, что это кое-что изменилось в последней версии SS. Когда я впервые написал это, мы использовали RAISERROR для обширного протоколирования ночных пакетных процессов с более чем 500 сообщениями, и это не было проблемой. Но за 7 лет многое может измениться.
Некоторые подробности в этом q stackoverflow.com/questions/20608989/…, почему это не работает в sqlcmd в последних версиях
По уведомлению @GendoIkari. Я пробовал с ssms от 2016SP1 с этим скриптом. На 500 он переключается на буферизацию 50 строк, а на 1k он переключается на 100 строк каждая. Так продолжалось как минимум до 2к, но потом я остановил скрипт. объявить @i int set @i = 0 объявить @t varchar (100), а 1 = 1 начать набор @i = @i + 1 set @t = 'print' + convert (varchar, @i) RAISERROR (@t, 10 , 1) С NOWAIT ждать окончания задержки '00: 00: 00.010 '
Да ... Первый параметр функции 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
Посмотрите на вкладку «Сообщения» внизу, рядом с вкладкой «Результаты», или переключитесь в режим «Результаты в текст».
Чтобы переключиться в режим «Результаты в текст», в SSMS выберите «Сервис» -> «Параметры» -> «Результаты запроса» -> SQL Server -> «Общие» -> «Место назначения по умолчанию для результатов» и выберите «Результаты в текст» вместо «Результаты в сетки», повторно -откройте окно запроса, и тогда вы не будете сидеть и смотреть на пустую вкладку результатов, как на пустышку, в то время как вывод RAISERROR переходит на вкладку сообщений.
Для справки: если вы работаете в скриптах (пакетная обработка), а не в хранимой процедуре, вывод промывки запускается командой GO, например
print 'test'
print 'test'
go
В общем, мой вывод следующий: вывод выполнения сценария mssql, выполняемого в графическом интерфейсе пользователя SMS или с помощью sqlcmd.exe, сбрасывается в файл, stdoutput, окно графического интерфейса при первом операторе GO или до конца сценария.
Очистка внутри хранимой процедуры работает по-другому, так как вы не можете поместить GO внутрь.
Ссылка: инструкция tsql Go
go не просто сбрасывает вывод, он завершает пакет в соответствии с предоставленной вами ссылкой. Все, что у вас declared, отбрасывается, поэтому не очень удобно для отладки. declare @test int print "I want to read this!" go set @test=5 выдает ошибку, утверждая, что @test не определен, потому что он находится в новой партии.
Я согласен, это неправильный ответ на этот вопрос, но я поставил ответ (см. Отказ от ответственности в начале), поскольку он может быть полезен для кого-то другого - например, кто-то, кто запускает пакетный sql.
Другой лучший вариант - не зависеть от PRINT или RAISERROR и просто загрузить свои операторы print в таблицу ## Temp в TempDB или в постоянную таблицу в вашей базе данных, которая сразу же предоставит вам видимость данных с помощью оператора SELECT из другого окна. . Это работает лучше всего для меня. Использование постоянной таблицы также служит журналом того, что произошло в прошлом. Операторы печати удобны для ошибок, но с помощью таблицы журнала вы также можете определить точную точку отказа на основе последнего зарегистрированного значения для этого конкретного выполнения (при условии, что вы отслеживаете общее время начала выполнения в таблице журнала).
Это может быть проблемой, если вы пишете действительно транзакционный сценарий с фиксацией и откатом. Я не верю, что вы сможете запросить свою временную таблицу вживую - и она исчезнет, если ваша транзакция не удастся.
@SteveJ, вы можете запросить его вживую, используя SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; в сеансе мониторинга
@TheConstructor; Это полезный совет - я воспользуюсь им, спасибо. Однако разве мы все еще не остались с временной таблицей, уходящей при откате? Если проводить анализ отказов, это будет большим недостатком.
@SteveJ Да, конечно, это есть. Конечно, вы можете скопировать данные из транзакции READ UNCOMMITTED в другую таблицу, но вы, вероятно, упустите момент непосредственно перед ROLLBACK. Так что это, вероятно, решает вопрос «как далеко?» а не «почему откат?»
Основываясь на ответе @JoelCoehoorn, мой подход состоит в том, чтобы оставить все мои операторы PRINT на месте и просто следовать им оператором RAISERROR, чтобы вызвать сброс.
Например:
PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT
Преимущество этого подхода в том, что операторы PRINT могут объединять строки, тогда как RAISERROR - нет. (Так что в любом случае у вас есть такое же количество строк кода, сколько вам нужно будет объявить и установить переменную для использования в RAISERROR).
Если, как и я, вы используете AutoHotKey или SSMSBoost или аналогичный инструмент, вы можете легко настроить ярлык, такой как «] flush», чтобы ввести за вас строку RAISERROR. Это экономит ваше время, если это одна и та же строка кода каждый раз, то есть ее не нужно настраивать для хранения определенного текста или переменной.
Обратите внимание, что RAISERROR() поддерживает строковую интерполяцию в стиле printf(). Например, если @MyVariableName является строковым типом (например, VARCHAR(MAX), NVARCHAR(MAX) и т. д.), Вы можете использовать RAISERROR() с одной строкой: RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName).
Это так удобно! Я знаю, что RAISERROR может выполнять простую замену, но попробуйте заменить время [дата] или вызвать функцию из оператора RAISERROR! Этот ответ дает вам простой FLUSH в форме появления пустой ошибки (за счет новой строки).
Небольшое замечание для людей, которые (как и я) думают, что ответы для них не работают: не забудьте переключиться на вкладку «Сообщения», когда выполняется запрос. По умолчанию вы увидите вкладку «Результаты».