Могу ли я запустить хранимую процедуру и немедленно вернуться, не дожидаясь ее завершения?

41

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

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

Есть ли способ заставить одну хранимую процедуру запустить вторую хранимую процедуру и сразу же вернуться, не дожидаясь результатов?

Я использую SQL Server 2005.

Рейчел
источник
Как вызываются хранимые процедуры? ASP.NET веб-приложение? SSRS?
мистер Браунстоун
@ Mr.Brownstone Обычно он вызывается из веб-приложения ASP.Net, хотя может вызываться более чем одним из них. Я должен был бы перепроверить. Он также иногда запускается вручную из SSRS.
Рэйчел
@MartinSmith В прошлом я однажды работал с брокером служб SQL и надеялся, что будет более простой способ. Кажется, что такая сложная установка для чего-то такого простого, как это.
Рэйчел
1
@MartinSmith - это почти то, о чем я думал, а также, что касается SSRS, нет, вы не можете, но можете сделать это, включив Report Viewer в приложение и переместив в него свои rdl - таким образом, можно было бы выполнять асинхронные вызовы. для отчетов, а также.
мистер Браунстоун

Ответы:

27

Похоже, что для этого есть несколько способов, но я обнаружил, что самым простым способом было предложение Мартина настроить процедуру в задании SQL и запустить ее с помощью асинхронной команды sp_start_job из моей хранимой процедуры.

EXEC msdb.dbo.sp_start_job @job_name='Run2ndStoredProcedure'

Это работает только для меня, потому что мне не нужно указывать какие-либо параметры для моей хранимой процедуры.

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

  • Использование SQL Service Broker, как предлагают Мартин и Себастьян . Это, вероятно, лучшее предложение, если вы не возражаете против сложности его настройки и изучения его работы.
  • Асинхронное выполнение процесса в коде, который отвечает за выполнение хранимой процедуры, как предложил Mr.Brownstone .

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

  • Заставьте 1-ю процедуру установить флаг и настройте повторяющееся задание, чтобы проверить этот флаг и запустить, если он установлен, как предложил Джимбо . Я не большой поклонник заданий, которые выполняются постоянно и проверяют наличие изменений каждые несколько минут, но это, безусловно, стоит рассмотреть в зависимости от вашей ситуации.
Рейчел
источник
4
Посмотрите на Асинхронное выполнение процедур для готового к использованию примера с использованием Service Broker. Преимущество перед sp_job заключается в том, что он работает в Express Edition и полностью содержит БД (не зависит от таблиц заданий MSDB). Последнее очень важно для восстановления после отказа DBM и восстановления HA / DR.
Ремус Русану
Стреляй, я вижу, что Мартин связал ту же статью. Я оставлю комментарий для аргументов аварийного переключения / DR.
Ремус Русану
@RemusRusanu: хорошо, это один из лучших источников информации о Service Broker, но я полагаю, вы уже знали ;-).
Marian
Мне понравилась ссылка от @Rusanu, но я хотел что-то без ответа (что, я думаю, соответствует этой проблеме). Я написал свою упрощенную версию на abamacus.blogspot.com/2016/05/…
Abacus
Кроме того, если вы попытаетесь запустить задание агента SQL, оно не будет выполнено EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'., так как ни компонент Service Broker, ни агент Sql не существуют в Azure. Я не знаю, почему Microsoft после полутора десятилетий опрошенных отказывается добавлять EXECUTE ASYNC RematerializeExpensiveCacheTable.
Ян Бойд
8

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

Себастьян Майн
источник
7

Этот старый вопрос заслуживает более полного ответа. Некоторые из них упоминаются здесь в других ответах / комментариях, другие могут или не могут работать для конкретной ситуации OP, но могут работать для других, ищущих асинхронный вызов хранимых процедур из SQL.

Просто чтобы быть абсолютно четко: TSQL делает не (само по себе) имеют возможность запускать другие операции Tsql асинхронно .

Это не значит, что у вас еще не так много вариантов:

  • Задания агента SQL : создайте несколько заданий SQL и либо запланируйте их выполнение в нужное время, либо запустите их асинхронно из хранимого процесса «главный элемент управления», используя sp_start_job. Если вам нужно контролировать их прогресс программно, просто убедитесь, что каждое из заданий обновляет пользовательскую таблицу JOB_PROGRESS (или вы можете проверить, закончили ли они еще, используя недокументированную функцию, xp_sqlagent_enum_jobsкак описано в этой замечательной статье Грегори А. Ларсена). Вам нужно создать столько отдельных заданий, сколько вы хотите, чтобы выполнялись параллельные процессы, даже если они запускают один и тот же хранимый процесс с разными параметрами.
  • Пакет служб SSIS . Для более сложных асинхронных сценариев создайте пакет служб SSIS с простым потоком задач ветвления. Службы SSIS будут запускать эти задачи в отдельных спидах, которые SQL будет выполнять параллельно. Вызовите пакет служб SSIS из задания агента SQL.
  • Пользовательское приложение : создайте простое пользовательское приложение на языке по вашему выбору (C #, Powershell и т. Д.), Используя асинхронные методы, предоставляемые этим языком. Вызовите хранимую процедуру SQL в каждом потоке приложения.
  • Автоматизация OLE : В SQL используйте sp_oacreateи sp_oamethodдля запуска нового процесса, вызывающего друг друга хранимым процессом, как описано в этой статье , также Грегори А. Ларсен.
  • Компонент Service Broker . Рассмотрим использование компонента Service Broker , который является хорошим примером асинхронного выполнения в этой статье .
  • CLR Параллельное выполнение : С помощью команды CLR Parallel_AddSqlи , Parallel_Executeкак описано в этой статье Алан Каплан (SQL2005 + только).
  • Запланированные задачи Windows : перечислены для полноты, но я не фанат этой опции.

Если бы это был я, я бы, вероятно, использовал несколько заданий агента SQL в более простых сценариях и пакет служб SSIS в более сложных сценариях.

В вашем случае вызов заданий агента SQL звучит как простой и управляемый выбор.

Последний комментарий : SQL уже пытается распараллеливать отдельные операции, когда это возможно *. Это означает, что выполнение 2 задач одновременно, а не после друг друга, не гарантирует, что оно завершится раньше. Проверьте внимательно, чтобы увидеть, действительно ли это что-то улучшает или нет.

У нас был разработчик, который создал пакет DTS для одновременного запуска 8 задач. К сожалению, это был только 4-х процессорный сервер :)

* Предполагая настройки по умолчанию. Это можно изменить, изменив максимальную степень параллелизма или маску сходства на сервере, или воспользовавшись подсказкой запроса MAXDOP.

BradC
источник
Привет бред Я должен верить, что вы можете запустить несколько заданий агента SQL из одного задания агента SQL, и они (кратные) будут работать асинхронно. Я считаю, что единственным критерием успеха на уровне родительской работы является то, что была запущена дополнительная работа. Отказ (я думаю) можно увидеть, только просмотрев историю вспомогательных заданий.
user8591443
@ user8591443 Для этого основного задания, которое вы описываете, нужно будет использовать сценарий SQL, который запускает другие задания с помощью sp_start_job, как я описал в своей первой статье (поскольку нет встроенного типа шага задания «начать другое задание»). Но я думаю, что вы правы в отношении отдельных статусов работы, не сводящихся к мастеру; вам нужно будет запросить статус неудачи / успеха индивидуально.
BradC
да, каждый шаг агента (по одному на каждое задание) в задании основного агента sql будет иметь отдельный t-sql exec sp_start_job.
user8591443
6

Да, один метод:

  1. Когда первая хранимая процедура завершена, она вставляет запись со всей информацией, необходимой для запуска второй хранимой процедуры.
  2. Вторая хранимая процедура выполняется как задание, каждую минуту или в какое время вы решаете
  3. Он проверяет наличие вставленных записей, обрабатывает их и помечает запись как завершенную.
Джимбо
источник
Это ограничивает выполнение хранимой процедуры количеством заданий, которые вы выполняете, и если вы хотите, чтобы это вызывалось только одним клиентом за раз, это нормально, тогда как у вас может быть несколько клиентов, вызывающих одну и ту же процедуру одновременно , Кроме того, как клиент узнает, что задание завершено, без повторного опроса базы данных, чтобы узнать, был ли установлен флаг?
мистер Браунстоун
1
@ Mr.Brownstone - Потенциально задание может обрабатывать более одной невыполненной задачи, поставленной в очередь различными вызовами хранимых процедур при запуске. Хранимая процедура может также вызываться sp_start_jobдля ее запуска или динамического создания заданий по мере необходимости, чтобы избежать опроса каждую минуту, но сложность для этого случая, вероятно, означает, что она будет не проще, чем брокер служб.
Мартин Смит
@MartinSmith У меня уже есть настройка задания для этой 2-й хранимой процедуры, так как раньше она запускалась по ночам, пока мы не обнаружили, что некоторые проблемы с ней неправильно синхронизируются с номерами 1-й процедуры. Если я начну задание с 1-й хранимой процедуры, будет ли оно выполняться асинхронно и немедленно вернуться из SP?
Рэйчел
@Рэйчел - Да. sp_start_jobвозвращается немедленно. Не могу вспомнить, какие разрешения ему нужны.
Мартин Смит
1
Запуск задания из другой процедуры / базы данных - довольно сложная проблема, если вы не хотите открывать большие дыры в безопасности. Erland Sommarskog имеет статью о различных техниках, которые вам нужно объединить: sommarskog.se/grantperm.html Однако там нет полного решения.
Себастьян Майн
1

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

Пако
источник
3
Первая хранимая процедура не вернется, пока не завершится вставка в таблицу аудита, и этого не произойдет, пока не завершится выполнение триггера (включая вызов 2-й хранимой процедуры)
Martin Smith
1
Я уже изучал использование триггера, но триггеры запускаются синхронно с оператором INSERTили UPDATE, а не асинхронно, поэтому Мартин прав, что 1-я процедура все равно будет ждать до тех пор, пока 2-я процедура не завершится.
Рэйчел