Kann ich eine gespeicherte Prozedur starten und sofort zurückkehren, ohne auf den Abschluss zu warten?

41

Wir haben eine gespeicherte Prozedur, die Benutzer manuell ausführen können, um aktualisierte Zahlen für einen Bericht zu erhalten, der den ganzen Tag über verwendet wird.

Ich habe eine zweite gespeicherte Prozedur, die ausgeführt werden sollte, nachdem die erste gespeicherte Prozedur ausgeführt wurde, da sie auf den Zahlen basiert, die von dieser ersten gespeicherten Prozedur abgerufen wurden. Die Ausführung dauert jedoch länger und ist für einen separaten Prozess vorgesehen Lassen Sie den Benutzer warten, während diese zweite gespeicherte Prozedur ausgeführt wird.

Gibt es eine Möglichkeit, eine gespeicherte Prozedur eine zweite gespeicherte Prozedur starten zu lassen und sofort zurückzukehren, ohne auf Ergebnisse zu warten?

Ich verwende SQL Server 2005.

Rachel
quelle
Wie werden die gespeicherten Prozeduren aufgerufen? ASP.NET-Webanwendung? SSRS?
Mr. Brownstone
@ Mr.Brownstone Es wird normalerweise von einer ASP.Net-Webanwendung aufgerufen, obwohl es möglicherweise von mehr als einer von ihnen aufgerufen wird. Ich würde es noch einmal überprüfen müssen. Es wird gelegentlich auch manuell von SSRS ausgeführt.
Rachel
@MartinSmith Ich habe in der Vergangenheit einmal mit dem SQL-Service-Broker zusammengearbeitet und gehofft, dass es einen einfacheren Weg gibt. Es scheint ein so komplexer Aufbau für so etwas Einfaches zu sein.
Rachel
1
@MartinSmith Das ist ziemlich genau das, was ich gedacht habe - auch, da Sie für SSRS keine andere Möglichkeit haben, als den Report Viewer in die Anwendung einzubinden und Ihre Rdls in die Anwendung zu verschieben - auf diese Weise wäre es möglich, asynchrone Anrufe zu tätigen auch für die Berichte.
Mr. Brownstone

Antworten:

27

Es sieht so aus, als gäbe es mehrere Möglichkeiten, um dies zu erreichen. Am einfachsten fand ich jedoch Martins Vorschlag , die Prozedur in einem SQL-Job einzurichten und sie mit dem asynchronen Befehl sp_start_job aus meiner gespeicherten Prozedur zu starten .

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

Dies funktioniert nur bei mir, da ich keine Parameter für meine gespeicherte Prozedur angeben muss.

Andere Vorschläge, die je nach Ihrer Situation funktionieren können, sind

  • Verwenden Sie den SQL Service Broker, wie es Martin und Sebastian vorschlagen. Dies ist wahrscheinlich der beste Vorschlag, wenn Ihnen die Komplexität des Einrichtens und das Erlernen der Funktionsweise nichts ausmacht.
  • Führen Sie den Prozess asynchron in dem Code aus, der für die Ausführung der gespeicherten Prozedur verantwortlich ist, wie von Mr.Brownstone vorgeschlagen .

    Keine schlechte Idee, aber in meinem Fall wird die gespeicherte Prozedur von mehreren Stellen aufgerufen, sodass es nicht so praktisch erschien, alle diese Stellen zu finden und sicherzustellen, dass sie auch die zweite Prozedur aufrufen. Außerdem ist die zweite gespeicherte Prozedur ziemlich kritisch, und das Nichtausführen dieser Prozedur kann zu erheblichen Problemen für unser Unternehmen führen.

  • Setzen Sie mit der ersten Prozedur ein Flag und richten Sie einen wiederkehrenden Job ein, um nach diesem Flag zu suchen und zu prüfen, ob es gesetzt ist, wie es Jimbo vorgeschlagen hat . Ich bin kein großer Fan von Jobs, die ständig laufen und alle paar Minuten nach Änderungen suchen, aber es ist sicherlich eine Option, die es wert ist, je nach Ihrer Situation in Betracht gezogen zu werden.
Rachel
quelle
3
Unter Asynchrone Prozedurausführung finden Sie ein einsatzbereites Beispiel für die Verwendung von Service Broker. Der Vorteil gegenüber sp_job ist, dass es auf der Express Edition funktioniert und vollständig in der Datenbank enthalten ist (keine Abhängigkeit von MSDB-Jobtabellen). Letzteres ist beim DBM-Failover und bei der HA / DR-Wiederherstellung sehr wichtig.
Remus Rusanu
Shoot, ich sehe Martin den gleichen Artikel verlinkt. Ich werde den Kommentar für die Failover / DR-Argumente hinterlassen.
Remus Rusanu
@RemusRusanu: Nun, das ist eine der besten Informationsquellen in Bezug auf Service Broker, aber ich nehme an, Sie haben es bereits gewusst ;-).
Marian
Ich mochte den Link von @ Rusanu, aber ich wollte etwas ohne Antwort (was meiner Meinung nach zu diesem Problem passt). Ich schrieb meine vereinfachte Version auf abamacus.blogspot.com/2016/05/…
Abacus
Auch wenn Sie versuchen, einen SQL Agent-Auftrag zu starten EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'., schlägt dies fehl, wenn der Service Broker oder SQL Agent ebenfalls nicht in Azure vorhanden ist. Ich weiß nicht, warum sich Microsoft nach anderthalb Jahrzehnten der Nachfrage weigert, etwas hinzuzufügen EXECUTE ASYNC RematerializeExpensiveCacheTable.
Ian Boyd
8

Sie können den Service Broker zusammen mit der Aktivierung in der Warteschlange verwenden. Damit können Sie die Parameter für den Prozeduraufruf in die Warteschlange stellen. Das dauert ungefähr so ​​lange wie eine Beilage. Nach dem Festschreiben der Transaktion und möglicherweise noch ein paar Sekunden ruft die Aktivierung die Empfängerprozedur automatisch asynchron auf. Es ist dann nur noch nötig, die Parameter der Warteschlange zu übernehmen und die gewünschte Arbeit zu erledigen.

Sebastian Meine
quelle
7

Diese alte Frage verdient eine umfassendere Antwort. Einige davon werden hier in anderen Antworten / Kommentaren erwähnt, andere funktionieren möglicherweise für die spezifische Situation von OP oder nicht, aber möglicherweise auch für andere, die gespeicherte Prozesse asynchron aus SQL aufrufen möchten.

Nur um ganz ausdrücklich: TSQL tut nicht (selbst) haben die Fähigkeit , asynchron andere TSQL Operationen zu starten .

Das bedeutet nicht, dass Sie noch nicht viele Optionen haben:

  • SQL Agent-Jobs : Erstellen Sie mehrere SQL-Jobs und planen Sie sie entweder für die Ausführung zum gewünschten Zeitpunkt oder starten Sie sie asynchron von einem gespeicherten "Master-Control" -Prozess aus sp_start_job. Wenn Sie ihren Fortschritt programmgesteuert überwachen müssen, stellen Sie einfach sicher, dass die Jobs jeweils eine benutzerdefinierte JOB_PROGRESS-Tabelle aktualisieren (oder überprüfen Sie, ob sie die undokumentierte Funktion, xp_sqlagent_enum_jobswie in diesem hervorragenden Artikel von Gregory A. Larsen beschrieben, bereits verwendet haben). Sie müssen so viele separate Jobs erstellen, wie Sie möchten, dass parallele Prozesse ausgeführt werden, auch wenn sie denselben gespeicherten Prozess mit unterschiedlichen Parametern ausführen.
  • SSIS-Paket : Erstellen Sie für komplexere asynchrone Szenarien ein SSIS-Paket mit einem einfachen Ablauf für Verzweigungsaufgaben. SSIS startet diese Aufgaben in einzelnen Spids, die SQL parallel ausführt. Rufen Sie das SSIS-Paket von einem SQL Agent-Job aus auf.
  • Benutzerdefinierte Anwendung : Erstellen Sie eine einfache benutzerdefinierte Anwendung in der Sprache Ihrer Wahl (C #, Powershell usw.), und verwenden Sie dabei die von dieser Sprache bereitgestellten asynchronen Methoden. Rufen Sie für jeden Anwendungsthread einen gespeicherten SQL-Prozess auf.
  • OLE-Automatisierung : Verwenden Sie in SQL sp_oacreateund sp_oamethod, um einen neuen Prozess zu starten, der sich gegenseitig gespeicherte Prozesse aufruft, wie in diesem Artikel beschrieben , ebenfalls von Gregory A. Larsen.
  • Service Broker : Sehen Sie sich Service Broker an , ein gutes Beispiel für die asynchrone Ausführung in diesem Artikel .
  • CLR-Parallelausführung : Verwenden Sie die CLR-Befehle Parallel_AddSqlund Parallel_Executewie in diesem Artikel von Alan Kaplan beschrieben (nur SQL2005 +).
  • Geplante Windows-Aufgaben : Der Vollständigkeit halber aufgeführt, aber ich bin kein Fan dieser Option.

Wenn ich es wäre, würde ich wahrscheinlich in einfacheren Szenarien mehrere SQL Agent-Jobs und in komplexeren Szenarien ein SSIS-Paket verwenden.

In Ihrem Fall klingt das Aufrufen von SQL Agent-Jobs nach einer einfachen und verwaltbaren Wahl.

Ein letzter Kommentar : SQL versucht bereits, einzelne Operationen zu parallelisieren, wann immer dies möglich ist *. Dies bedeutet, dass das gleichzeitige Ausführen von zwei Aufgaben anstelle von zwei Aufgaben nacheinander keine Garantie dafür ist, dass die Aufgabe früher abgeschlossen wird. Testen Sie sorgfältig, ob es tatsächlich etwas verbessert oder nicht.

Wir hatten einen Entwickler, der ein DTS-Paket erstellt hat, um 8 Aufgaben gleichzeitig auszuführen. Leider war es nur ein 4-CPU-Server :)

* Vorausgesetzt, Standardeinstellungen. Dies kann durch Ändern des Maximalgrads der Parallelität oder der Affinitätsmaske des Servers oder durch Verwenden des MAXDOP-Abfragehinweises geändert werden.

BradC
quelle
6

Ja, eine Methode:

  1. Wenn die erste gespeicherte Prozedur abgeschlossen ist, wird ein Datensatz mit allen Informationen eingefügt, die für die Ausführung der zweiten gespeicherten Prozedur erforderlich sind
  2. Die zweite gespeicherte Prozedur wird jede Minute oder zu der von Ihnen festgelegten Zeit als Job ausgeführt
  3. Es prüft auf eingefügte Datensätze, führt den Vorgang durch und markiert den Datensatz als vollständig
Jimbo
quelle
Dies beschränkt die Ausführung der gespeicherten Prozedur auf die Anzahl der ausgeführten Jobs. Wenn Sie jedoch immer nur möchten, dass dies von einem Client gleichzeitig aufgerufen wird, ist dies in Ordnung. Möglicherweise rufen jedoch mehrere Clients dieselbe Prozedur gleichzeitig auf . Wie würde der Client auch wissen, dass der Auftrag abgeschlossen wurde, ohne wiederholt die Datenbank abzufragen, um herauszufinden, ob ein Flag gesetzt wurde?
Mr. Brownstone
1
@ Mr.Brownstone - Möglicherweise kann der Job mehr als eine ausstehende Aufgabe verarbeiten, die von verschiedenen Aufrufen gespeicherter Prozeduren in die Warteschlange gestellt wurde, wenn sie ausgeführt wird. Möglicherweise ruft die gespeicherte Prozedur auch sp_start_jobauf, um sie zu starten, oder erstellt Jobs nach Bedarf dynamisch, um nicht jede Minute abzufragen. In diesem Fall bedeutet die Komplexität jedoch wahrscheinlich, dass sie nicht einfacher als der Service Broker ist.
Martin Smith
@MartinSmith Ich habe tatsächlich bereits ein Job-Setup für diese zweite gespeicherte Prozedur, da sie in der Nacht ausgeführt wurde, bis wir einige Probleme damit fanden, dass sie nicht richtig mit den Nummern der ersten Prozedur synchronisiert wurde. Wenn ich den Job von der ersten gespeicherten Prozedur aus starte, wird er dann asynchron ausgeführt und kehrt sofort vom SP zurück?
Rachel
@ Rachel - Ja. sp_start_jobkehrt sofort zurück. Ich kann mich nicht erinnern, welche Berechtigungen es benötigt.
Martin Smith
1
Das Starten eines Jobs von einer anderen Prozedur / Datenbank aus ist ein ziemlich komplexes Problem, wenn Sie keine großen Sicherheitslücken öffnen möchten. Erland Sommarskog hat einen Artikel über die verschiedenen Techniken, die Sie kombinieren müssen: sommarskog.se/grantperm.html Es gibt jedoch keine vollständige Lösung.
Sebastian Meine
1

Eine andere Möglichkeit wäre, die erste gespeicherte Prozedur zum Schreiben in eine Überwachungstabelle zu veranlassen, wenn sie abgeschlossen ist, und einen Auslöser in der Überwachungstabelle zu platzieren, der die zweite gespeicherte Prozedur startet, wenn in die Überwachungstabelle geschrieben wird. Es muss nicht ständig abgefragt werden und es ist kein zusätzlicher SQL Server-Agent-Job erforderlich.

paco
quelle
3
Die erste gespeicherte Prozedur würde nicht zurückkehren, bis die Einfügung in die Überwachungstabelle abgeschlossen ist, und dies würde nicht geschehen, bis die Ausführung des Auslösers abgeschlossen ist (einschließlich des Aufrufs der zweiten gespeicherten Prozedur)
Martin Smith,
1
Ich habe bereits versucht, einen Trigger zu verwenden, aber die Trigger werden synchron mit der Anweisung INSERTor UPDATEund nicht asynchron ausgeführt. Martin hat also Recht, dass die erste Prozedur immer noch darauf wartet, bis die zweite Prozedur beendet ist, um zurückzukehren.
Rachel