Posso iniciar um procedimento armazenado e retornar imediatamente sem esperar que ele termine?

41

Temos um procedimento armazenado que os usuários podem executar manualmente para obter alguns números atualizados de um relatório usado constantemente ao longo do dia.

Eu tenho um segundo procedimento armazenado que deve ser executado após a execução do primeiro procedimento armazenado, pois é baseado nos números obtidos com esse primeiro procedimento armazenado, no entanto, leva mais tempo para ser executado e é para um processo separado, por isso não quero faça o usuário esperar enquanto este segundo procedimento armazenado é executado.

Existe uma maneira de um procedimento armazenado iniciar um segundo procedimento armazenado e retornar imediatamente sem aguardar resultados?

Estou usando o SQL Server 2005.

Rachel
fonte
Como os procedimentos armazenados estão sendo chamados? Aplicativo da Web ASP.NET? SSRS?
Mr.Brownstone
@ Mr.Brownstone Geralmente é chamado de um aplicativo Web ASP.Net, embora possa estar sendo chamado por mais de um deles. Eu teria que checar. Ocasionalmente, também é executado manualmente a partir do SSRS.
22413 Rachel
@ MartinSmith Eu trabalhei uma vez com o corretor de serviços SQL no passado e esperava que houvesse uma maneira mais simples. Parece uma configuração tão complexa para algo tão simples quanto isso.
22413 Rachel
1
@MartinSmith é exatamente o que eu estava pensando - também, quanto ao SSRS, você não pode, mas o que você poderia fazer é incorporar o Report Viewer no aplicativo e mover seus rdls para ele - para que seja possível fazer chamadas assíncronas para os relatórios também.
Mr.Brownstone

Respostas:

27

Parece que existem várias maneiras de fazer isso, mas achei que a maneira mais simples foi a sugestão de Martin de configurar o procedimento em um trabalho SQL e iniciá-lo usando o comando asynchronous sp_start_job do meu procedimento armazenado.

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

Isso só funciona para mim porque não preciso especificar nenhum parâmetro para o meu procedimento armazenado.

Outras sugestões que podem funcionar dependendo da sua situação são

  • Usando o SQL Service Broker, como Martin e Sebastian sugerem. Essa é provavelmente a melhor sugestão se você não se importa com a complexidade de configurá-lo e aprender como ele funciona.
  • Executar o processo de forma assíncrona no código responsável pela execução do procedimento armazenado, como sugerido pelo Sr.Brownstone .

    Não é uma má idéia, no entanto, no meu caso, o procedimento armazenado é chamado de vários locais, portanto, encontrar todos esses locais e garantir que eles chamam o segundo procedimento também não parecia tão prático. Além disso, o segundo procedimento armazenado é bastante crítico, e esquecer de executá-lo pode causar alguns problemas importantes para a nossa empresa.

  • Faça o 1º procedimento definir um sinalizador e configure um trabalho recorrente para verificar esse sinalizador e executar se estiver definido, como sugeriu Jimbo . Eu não sou um grande fã de trabalhos que são executados constantemente e verificam mudanças a cada poucos minutos, mas certamente é uma opção que vale a pena considerar, dependendo da sua situação.
Rachel
fonte
3
Dê uma olhada em Execução de procedimentos assíncronos para obter um exemplo pronto para usar usando o Service Broker. As vantagens sobre o sp_job é que ele funciona no Express Edition e é totalmente contido no banco de dados (sem dependência das tabelas de tarefas do MSDB). O posterior é muito importante no failover do DBM e na recuperação de HA / DR.
Remus Rusanu
Atire, vejo Martin vinculado ao mesmo artigo. Deixarei o comentário para os argumentos de failover / DR.
Remus Rusanu
@RemusRusanu: bem, essa é uma das melhores fontes de informações sobre o Service Broker, mas suponho que você já sabia ;-).
Marian
Gostei do link do @Rusanu, mas queria algo sem resposta (o que acho que corresponde a esse problema). Eu escrevi minha versão simplificada em abamacus.blogspot.com/2016/05/…
Abacus
Além disso, se você tentar iniciar um trabalho do SQL Agent, ele falhará com O EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'.Também nem o Service Broker, nem o Sql Agent, existem no Azure. Não sei por que a Microsoft, depois de uma década e meia de pessoas perguntando, se recusa a adicionar EXECUTE ASYNC RematerializeExpensiveCacheTable.
Ian Boyd
8

Você poderia usar o service broker juntamente com a ativação na fila. Com isso, você pode postar os parâmetros para a chamada de procedimento na fila. Isso leva tanto tempo quanto uma inserção. Depois que a transação é confirmada e, potencialmente, mais alguns segundos, a ativação chama automaticamente o procedimento do receptor de forma assíncrona. É necessário apenas pegar os parâmetros da fila e fazer o trabalho desejado.

Sebastian Meine
fonte
7

Esta pergunta antiga merece uma resposta mais abrangente. Alguns deles são mencionados em outras respostas / comentários aqui, outros podem ou não funcionar para a situação específica do OP, mas podem funcionar para outros que procuram chamar procs armazenados de forma assíncrona a partir do SQL.

Apenas para ser totalmente explícito: o TSQL não possui (por si só) a capacidade de iniciar outras operações do TSQL de forma assíncrona .

Isso não significa que você ainda não tem muitas opções:

  • Tarefas do SQL Agent : Crie várias tarefas SQL e agende-as para serem executadas no momento desejado ou inicie-as de forma assíncrona a partir de um processo armazenado "controle mestre" sp_start_job. Se você precisar monitorar o progresso deles programaticamente, verifique se os trabalhos atualizam uma tabela JOB_PROGRESS personalizada (ou verifique se eles terminaram de usar a função não documentada, xp_sqlagent_enum_jobsconforme descrito neste excelente artigo de Gregory A. Larsen). Você deve criar quantos trabalhos separados desejar para que processos paralelos sejam executados, mesmo se eles estiverem executando o mesmo processo armazenado com parâmetros diferentes.
  • Pacote SSIS : para cenários assíncronos mais complicados, crie um pacote SSIS com um fluxo de tarefas de ramificação simples. O SSIS iniciará essas tarefas em spids individuais, que o SQL executará em paralelo. Chame o pacote SSIS de um trabalho do agente SQL.
  • Aplicativo personalizado : escreva um aplicativo personalizado simples no idioma de sua escolha (C #, Powershell etc.), usando os métodos assíncronos fornecidos por esse idioma. Chame um proc armazenado SQL em cada encadeamento de aplicativo.
  • Automação OLE : No SQL, use sp_oacreatee sp_oamethodpara iniciar um novo processo chamando um ao outro proc armazenado, conforme descrito neste artigo , também por Gregory A. Larsen.
  • Service Broker : examine o uso do Service Broker , um bom exemplo de execução assíncrona neste artigo .
  • Execução paralela do CLR : use os comandos CLR Parallel_AddSqle Parallel_Executeconforme descrito neste artigo por Alan Kaplan (somente SQL2005 +).
  • Tarefas agendadas do Windows : listadas quanto à integridade, mas não sou fã dessa opção.

Se fosse eu, provavelmente usaria vários trabalhos do SQL Agent em cenários mais simples e um pacote SSIS em cenários mais complexos.

No seu caso, chamar os trabalhos do SQL Agent parece uma opção simples e gerenciável.

Um comentário final : o SQL já tenta paralelizar operações individuais sempre que pode *. Isso significa que a execução de duas tarefas ao mesmo tempo, em vez de uma após a outra, não garante que elas terminem mais cedo. Teste com cuidado para ver se ele realmente melhora alguma coisa ou não.

Tivemos um desenvolvedor que criou um pacote DTS para executar 8 tarefas ao mesmo tempo. Infelizmente, era apenas um servidor com 4 CPUs :)

* Assumindo configurações padrão. Isso pode ser modificado alterando o Grau máximo de paralelismo ou Máscara de afinidade do servidor ou usando a dica de consulta MAXDOP.

BradC
fonte
6

Sim, um método:

  1. Quando o 1º procedimento armazenado é concluído, ele insere um registro com todas as informações necessárias para a execução do segundo procedimento armazenado
  2. O segundo procedimento armazenado é executado como um trabalho, a cada minuto ou a que horas você decide
  3. Ele verifica os registros inseridos, realiza seu processo e marca o registro como completo
Jimbo
fonte
Isso limita a execução do procedimento armazenado ao número de tarefas que você está executando, as quais, se você quiser que isso seja chamado por um cliente de cada vez, são boas - enquanto você pode ter vários clientes chamando o mesmo procedimento ao mesmo tempo . Além disso, como o cliente saberia que o trabalho foi concluído sem pesquisar repetidamente o banco de dados para descobrir se um sinalizador foi definido?
Mr.Brownstone
1
@ Mr.Brownstone - Potencialmente, o trabalho pode processar mais de uma tarefa pendente enfileirada por diferentes chamadas de procedimentos armazenados quando é executada. O procedimento armazenado também pode ser chamado sp_start_jobpara iniciá-lo ou criar trabalhos conforme necessário dinamicamente para evitar pesquisas a cada minuto, mas a complexidade para esse caso provavelmente significa que não será mais simples que o service broker.
Martin Smith
@ MartinSmith Na verdade, eu já tenho uma configuração de trabalho para este segundo procedimento armazenado, pois costumava ser executado todas as noites até encontrarmos alguns problemas com o fato de não ser sincronizado corretamente com os números do 1º procedimento. Se eu iniciar o trabalho a partir do 1º procedimento armazenado, ele seria executado de forma assíncrona e retornaria do SP imediatamente?
22413 Rachel
@ Rachel - Sim. sp_start_jobretorna imediatamente. Não consigo lembrar de que permissões ele precisa.
Martin Smith
1
Iniciar um trabalho a partir de outro procedimento / banco de dados é um problema bastante complexo se você não deseja abrir grandes falhas de segurança. Erland Sommarskog tem um artigo sobre as diferentes técnicas que você precisa combinar: sommarskog.se/grantperm.html No entanto, não existe uma solução completa.
Sebastian Meine
1

Outra possibilidade seria fazer com que o primeiro procedimento armazenado grave em uma tabela de auditoria quando for concluído e coloque um gatilho na tabela de auditoria que inicia o segundo procedimento armazenado quando a tabela de auditoria é gravada. Não é necessário pesquisar continuamente e não é necessário um trabalho extra do SQL Server Agent.

paco
fonte
3
O primeiro procedimento armazenado não retornaria até a inserção aos concluída tabela de auditoria e que não aconteceria até o gatilho terminou de execução (incluindo a chamada para o procedimento armazenado 2º)
Martin Smith
1
Eu já procurei usar um Trigger, mas os gatilhos são executados de forma síncrona com a instrução INSERTou UPDATE, não de forma assíncrona, portanto, Martin está certo de que o primeiro procedimento continuaria esperando até o retorno do segundo.
19413 Rachel