¿Puedo iniciar un procedimiento almacenado e inmediatamente regresar sin esperar a que termine?

41

Tenemos un procedimiento almacenado que los usuarios pueden ejecutar manualmente para obtener algunos números actualizados para un informe que se usa constantemente durante todo el día.

Tengo un segundo procedimiento almacenado que debe ejecutarse después de que se ejecute el primer procedimiento almacenado, ya que se basa en los números obtenidos de este primer procedimiento almacenado, sin embargo, toma más tiempo ejecutarlo y es para un proceso separado, por lo que no quiero hacer que el usuario espere mientras se ejecuta este segundo procedimiento almacenado.

¿Hay alguna manera de hacer que un procedimiento almacenado comience un segundo procedimiento almacenado y regrese inmediatamente sin esperar los resultados?

Estoy usando SQL Server 2005.

Rachel
fuente
¿Cómo se llaman los procedimientos almacenados? Aplicación web ASP.NET? SSRS?
Mr.Brownstone
@ Mr.Brownstone Por lo general, se llama desde una aplicación web ASP.Net, aunque puede estar siendo llamado por más de uno de ellos. Tendría que verificar dos veces. También ocasionalmente se ejecuta manualmente desde SSRS.
Rachel
@MartinSmith He trabajado una vez con el agente de servicios SQL en el pasado, y esperaba que hubiera una manera más simple. Parece una configuración tan compleja para algo tan simple como esto.
Rachel
1
@MartinSmith que es más o menos lo que estaba pensando, también, en cuanto a SSRS, no puedes pero lo que puedes hacer es incorporar Report Viewer en la aplicación y mover tus rdl a ella, de esa manera sería posible hacer llamadas asíncronas para los informes también.
Mr.Brownstone

Respuestas:

27

Parece que hay varias formas de lograr esto, pero descubrí que la forma más simple fue la sugerencia de Martin de configurar el procedimiento en un trabajo SQL y comenzarlo usando el comando asincrónico sp_start_job de mi procedimiento almacenado.

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

Esto solo funciona para mí porque no necesito especificar ningún parámetro para mi procedimiento almacenado.

Otras sugerencias que pueden funcionar dependiendo de su situación son

  • Usar el SQL Service Broker como sugieren Martin y Sebastian . Esta es probablemente la mejor sugerencia si no le importa la complejidad de configurarlo y aprender cómo funciona.
  • Ejecutar el proceso de forma asincrónica en el código responsable de ejecutar el procedimiento almacenado, como sugirió Mr.Brownstone .

    No es una mala idea, sin embargo, en mi caso, el procedimiento almacenado se llama desde varios lugares, por lo que encontrar todos esos lugares y asegurarse de que también llamen al segundo procedimiento no parecía tan práctico. Además, el segundo procedimiento almacenado es bastante crítico, y olvidar ejecutarlo podría causar algunos problemas importantes para nuestra empresa.

  • Haga que el primer procedimiento establezca un indicador, y configure un trabajo recurrente para verificar ese indicador y ejecutarlo, como sugirió Jimbo . No soy un gran admirador de los trabajos que se ejecutan constantemente y verifican los cambios cada pocos minutos, pero ciertamente es una opción que vale la pena considerar dependiendo de su situación.
Rachel
fuente
3
Eche un vistazo a la Ejecución asíncrona de procedimientos para ver un ejemplo listo para usar con Service Broker. Las ventajas sobre sp_job es que funciona en Express Edition y está completamente contenida en la base de datos (no depende de las tablas de trabajo de MSDB). Esto último es muy importante en la conmutación por error de DBM y en la recuperación de HA / DR.
Remus Rusanu
Dispara, veo que Martin ha vinculado el mismo artículo. Dejaré el comentario para los argumentos de failover / DR.
Remus Rusanu
@RemusRusanu: bueno, esa es una de las mejores fuentes de información sobre Service Broker, pero supongo que ya lo sabías ;-).
Marian
Me gustó el enlace de @Rusanu, pero quería algo sin respuesta (que creo que coincide con este problema). Escribí mi versión simplificada en abamacus.blogspot.com/2016/05/…
Abacus
Además, si intenta iniciar un trabajo del Agente SQL, se producirá un error con The EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'.Also, ni Service Broker ni Sql Agent existen en Azure. No sé por qué Microsoft, después de una década y media de personas preguntando, se niega a agregar EXECUTE ASYNC RematerializeExpensiveCacheTable.
Ian Boyd el
8

Puede usar Service Broker junto con la activación en la cola. Con eso, puede publicar los parámetros para la llamada al procedimiento en la cola. Eso lleva casi tanto tiempo como un inserto. Una vez que se confirma la transacción y potencialmente unos segundos más, la activación llamará automáticamente al procedimiento del receptor de forma asincrónica. Simplemente debe tomar los parámetros de la cola y hacer el trabajo deseado.

Sebastian Meine
fuente
7

Esta vieja pregunta merece una respuesta más completa. Algunos de estos se mencionan en otras respuestas / comentarios aquí, otros pueden o no funcionar para la situación específica de OP, pero pueden funcionar para otros que buscan llamar a los procedimientos almacenados asincrónicamente desde SQL.

Solo para ser totalmente explícito: TSQL no tiene (por sí mismo) la capacidad de lanzar otras operaciones TSQL de forma asincrónica .

Eso no significa que todavía no tenga muchas opciones:

  • Trabajos del Agente SQL : cree múltiples trabajos SQL, y prográmelos para que se ejecuten en el momento deseado, o inícielos asíncronamente desde un proceso almacenado de "control maestro" utilizando sp_start_job. Si necesita monitorear su progreso programáticamente, solo asegúrese de que cada trabajo actualice una tabla JOB_PROGRESS personalizada (o puede verificar si han terminado de usar la función no documentada xp_sqlagent_enum_jobscomo se describe en este excelente artículo de Gregory A. Larsen). Debe crear tantos trabajos separados como desee que se ejecuten los procesos paralelos, incluso si están ejecutando el mismo proceso almacenado con diferentes parámetros.
  • Paquete SSIS : para escenarios asincrónicos más complicados, cree un paquete SSIS con un flujo de tareas de ramificación simple. SSIS lanzará esas tareas en spids individuales, que SQL ejecutará en paralelo. Llame al paquete SSIS desde un trabajo de agente SQL.
  • Aplicación personalizada : escriba una aplicación personalizada simple en el idioma que elija (C #, Powershell, etc.), utilizando los métodos asincrónicos proporcionados por ese idioma. Llame a un proceso almacenado de SQL en cada subproceso de aplicación.
  • Automatización OLE : en SQL, use sp_oacreatey sp_oamethodpara iniciar un nuevo proceso que se llame entre sí a un proceso almacenado como se describe en este artículo , también por Gregory A. Larsen.
  • Service Broker : considere el uso de Service Broker , un buen ejemplo de ejecución asincrónica en este artículo .
  • Ejecución paralela de CLR : utilice los comandos CLR Parallel_AddSqly Parallel_Executecomo se describe en este artículo por Alan Kaplan (solo SQL2005 +).
  • Tareas programadas de Windows : enumeradas para completar, pero no soy fanático de esta opción.

Si fuera yo, probablemente usaría múltiples trabajos de Agente SQL en escenarios más simples y un paquete SSIS en escenarios más complejos.

En su caso, llamar a trabajos de Agente SQL suena como una opción simple y manejable.

Un comentario final : SQL ya intenta paralelizar operaciones individuales siempre que puede *. Esto significa que ejecutar 2 tareas al mismo tiempo en lugar de una tras otra no garantiza que terminará antes. Pruebe cuidadosamente para ver si realmente mejora algo o no.

Tuvimos un desarrollador que creó un paquete DTS para ejecutar 8 tareas al mismo tiempo. Desafortunadamente, solo era un servidor de 4 CPU :)

* Asumiendo la configuración predeterminada. Esto se puede modificar alterando el Grado máximo de paralelismo o la Máscara de afinidad del servidor, o utilizando la sugerencia de consulta MAXDOP.

BradC
fuente
6

Sí, un método:

  1. Cuando se completa el primer procedimiento almacenado, inserta un registro con toda la información necesaria para que se ejecute el segundo procedimiento almacenado
  2. El segundo procedimiento almacenado se ejecuta como un trabajo, cada minuto o a qué hora decide
  3. Comprueba si hay registros insertados, realiza su proceso y marca el registro como completo
Jimbo
fuente
Esto limita la ejecución del procedimiento almacenado a la cantidad de trabajos que está ejecutando, lo que si solo desea que un cliente llame a esto a la vez, está bien, mientras que puede tener varios clientes llamando al mismo procedimiento al mismo tiempo . Además, ¿cómo sabría el cliente que el trabajo se ha completado sin sondear repetidamente la base de datos para averiguar si se ha establecido un indicador?
Mr.Brownstone
1
@ Mr.Brownstone - Potencialmente, el trabajo podría procesar más de una tarea pendiente en cola por diferentes llamadas a procedimientos almacenados cuando se ejecuta. El procedimiento almacenado también podría llamar sp_start_jobpara iniciarlo o crear trabajos según sea necesario dinámicamente para evitar sondeos cada minuto, pero la complejidad para ese caso probablemente significa que no será más simple que el intermediario de servicios.
Martin Smith
@MartinSmith De hecho, ya tengo una configuración de trabajo para este segundo procedimiento almacenado, ya que solía ejecutarse todas las noches hasta que encontramos algunos problemas con que no se sincronizaba correctamente con los números del primer procedimiento. Si inicio el trabajo desde el primer procedimiento almacenado, ¿se ejecutará de forma asincrónica y volverá del SP inmediatamente?
Rachel
@ Rachel - Sí. sp_start_jobvuelve de inmediato. Sin embargo, no puedo recordar qué permisos necesita.
Martin Smith
1
Comenzar un trabajo desde otro procedimiento / base de datos es un problema bastante complejo si no desea abrir grandes agujeros de seguridad. Erland Sommarskog tiene un artículo sobre las diferentes técnicas que necesita combinar: sommarskog.se/grantperm.html Sin embargo, no hay una solución completa allí.
Sebastian Meine
1

Otra posibilidad sería obtener el primer procedimiento almacenado para escribir en una tabla de auditoría cuando se complete y colocar un disparador en la tabla de auditoría que inicie el segundo procedimiento almacenado cuando se escriba en la tabla de auditoría. No es necesario sondear continuamente y no es necesario un trabajo adicional del Agente SQL Server.

paco
fuente
3
El primer procedimiento almacenado no volvería hasta que se completara la inserción en la tabla de auditoría y eso no sucedería hasta que el disparador terminara de ejecutarse (incluida la llamada al segundo procedimiento almacenado)
Martin Smith
1
Ya busqué usar un disparador, pero los disparadores se ejecutan sincrónicamente con la instrucción INSERTo UPDATE, no de forma asíncrona, por lo que Martin tiene razón en que el primer procedimiento todavía terminaría esperando hasta que el segundo procedimiento termine de regresar.
Rachel