Выполнить оператор внутри транзакции, не вовлекая его в эту транзакцию - PullRequest
2 голосов
/ 22 октября 2019

У меня есть несколько операторов SQL в пакете, которые я хочу профилировать для производительности. С этой целью я создал хранимую процедуру, которая регистрирует время выполнения.

Однако я также хочу иметь возможность откатить изменения, которые выполняет основной пакет, при этом сохраняя журналы производительности.

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

Допустим, у нас есть такая ситуация:

BEGIN TRANSACTION
SET @StartTime = SYSDATETIME
-- Do stuff here
UPDATE ABC SET x = fn_LongRunningFunction(x)
EXECUTE usp_Log 'Do stuff', @StartTime
SET @StartTime = SYSDATETIME
-- Do more stuff here
EXEC usp_LongRunningSproc()
EXECUTE usp_Log 'Do more stuff', @StartTime
ROLLBACK

Как я могу сохранить результаты, которые usp_Log сохраняет в таблицу, не откатывая их назад вместе с изменениями, которые происходят в другом месте транзакции?

Мне кажется, что в идеале usp_Log как-то не включится в транзакцию, которая может быть откатана.

Я ищу решение, которое можно реализовать наиболее надежным способом, с наименьшим количеством кода или работы, и с наименьшим влиянием на производительность профилируемого скрипта.

РЕДАКТИРОВАТЬ

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

Ответы [ 4 ]

0 голосов
/ 08 ноября 2019

Другой, довольно неясный вариант - привязать другие сеансы к длительной транзакции для мониторинга.

В начале транзакции вызовите sp_getbindtoken и отобразите токен привязки.

Затем в другом сеансе вызовите sp_bindsession , и вы сможете проверитьпромежуточное состояние транзакции.

Или вы можете прочитать журналы с помощью (NOLOCK).

Или вы можете использовать RAISERROR WITH LOG для отправки отладочных сообщений клиенту иотразите их в журнале SQL.

Или вы можете использовать настраиваемые пользователем события трассировки, настраиваемые пользователем , и отслеживать их в SQL Trace или XEvents.

Или вы можете использовать Сервер с обратной связью настроен так, чтобы не распространять транзакцию.

0 голосов
/ 22 октября 2019

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

ОбычноРекомендуется использовать контекстное соединение внутри объектов CLR, когда это возможно, так как это упрощает многие вещи. Однако в вашем конкретном случае вы хотите отделиться от контекста (особенно от текущей транзакции), поэтому обычное соединение - это путь.

Caveat emptor : если вы никогда не баловалисьПрограммирование CLR в SQL Server раньше, вы можете найти кривую обучения слишком крутой. Это, а также объем реконфигурации сервера (как экземпляра SQL Server, так и базовой ОС), необходимый для его работы, также могут показаться чрезмерно дорогими и не стоить хлопот. Тем не менее, я бы посчитал это жизнеспособным подходом.

0 голосов
/ 08 ноября 2019

Итак, как упоминал Роджер выше, SQLCLR является одним из вариантов. Однако, поскольку SQLCLR не разрешен, вам не повезло.

В SQL Server 2017 есть еще один вариант, а именно использование инфраструктуры расширяемости SQL Server и поддержки Python.

Вы можете использовать это, чтобы получить код Python, который вызывает ваш экземпляр SQL Server и выполняет процедуру usp_log.

0 голосов
/ 22 октября 2019

Для этого вы можете использовать переменную таблицы. На переменные таблицы, как и на обычные переменные, ROLLBACK не влияет. Вам потребуется вставить данные журнала производительности в переменную таблицы, а затем вставить ее в обычную таблицу в конце процедуры после всех операторов COMMIT и ROLLBACK.

...