it-swarm.com.de

Führen Sie gespeicherte Prozeduren parallel aus

Ich möchte versuchen, dieselbe gespeicherte Prozedur mehrmals mit unterschiedlichen Parametern gleichzeitig auszuführen.

Ich verwende SQL 2014

Der Grund dafür ist, dass der Vorgang etwa 7 Stunden dauert. Es macht tatsächlich den gleichen Prozess viele Male. So kann beispielsweise eine neue Datenbank und Tabellen für jeden Zweig erstellt werden.

Ich möchte die gespeicherte Prozedur aufteilen, damit ich sie pro Zweig ausführen und dann jede Abfrage parallel ausführen kann. Ich habe dies getestet, indem ich es in separaten Abfragefenstern ausgeführt habe, und es läuft fast 80% schneller.

Kann mir jemand einen Dummies-Leitfaden zum parallelen Ausführen von Abfragen geben?

9
user124569

Irgendwann habe ich diese Frage bei StackOverflow beantwortet , aber es scheint nützlich zu sein, diese Informationen auch bei DBA.SE zu überarbeiten und zu aktualisieren.

Nur um ganz explizit zu sein: TSQL hat nicht (für sich) die Möglichkeit, andere TSQL-Operationen asynchron zu starten .

Das bedeutet nicht, dass Sie noch nicht viele Optionen haben (einige davon werden in anderen Antworten erwähnt):

  • SQL Agent-Jobs : Erstellen Sie mehrere SQL-Jobs und planen Sie entweder die Ausführung zum gewünschten Zeitpunkt oder starten Sie sie asynchron von einem gespeicherten "Master Control" -Prozess mit 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 Sie können überprüfen, ob sie noch fertig sind, indem Sie die undokumentierte Funktion xp_sqlagent_enum_jobs Verwenden, wie in this) beschrieben ausgezeichneter Artikel von Gregory A. Larsen). Sie müssen so viele separate Jobs erstellen, wie parallele Prozesse ausgeführt werden sollen, auch wenn sie denselben gespeicherten Prozess mit unterschiedlichen Parametern ausführen.
  • SSIS-Paket : Erstellen Sie ein SSIS-Paket mit einem einfachen Verzweigungs-Taskflow. SSIS startet diese Aufgaben in einzelnen Spids, die SQL parallel ausführt.
  • Benutzerdefinierte Anwendung : Schreiben Sie eine einfache benutzerdefinierte Anwendung in der Sprache Ihrer Wahl (C #, Powershell usw.) mit den von dieser Sprache bereitgestellten asynchronen Methoden. Rufen Sie einen gespeicherten SQL-Prozess für jeden Anwendungsthread auf.
  • OLE-Automatisierung : Verwenden Sie in SQL sp_oacreate Und sp_oamethod, Um einen neuen Prozess zu starten, der sich gegenseitig wie beschrieben speichert in dieser Artikel , ebenfalls von Gregory A. Larsen.
  • Service Broker : Sehen Sie sich die Verwendung von Service Broker an, a gutes Beispiel für die asynchrone Ausführung in diesem Artikel .
  • CLR Parallel Execution : Verwenden Sie die CLR-Befehle Parallel_AddSql Und Parallel_Execute Wie in dieser Artikel beschrieben = von Alan Kaplan (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 mehrere SQL Agent-Jobs in einfacheren Szenarien und ein SSIS-Paket in komplexeren Szenarien verwenden.

In Ihrem Fall klingen mehrere geplante Agent-Jobs wie eine einfache und überschaubare Wahl, es sei denn, Sie versuchen, 200 separate Threads zu starten.

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 statt nacheinander keine Garantie dafür ist, dass sie früher abgeschlossen werden. Testen Sie sorgfältig, ob sich 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 maximalen Parallelitätsgrads oder der Affinitätsmaske des Servers oder mithilfe des MAXDOP-Abfragehinweises geändert werden.

8
BradC

Am besten erstellen Sie drei separate Jobs mit demselben Zeitplan, um die Jobs gleichzeitig zu starten. Je nachdem, was die Jobs tun, sollten Sie darauf achten, das Blockieren und Deadlocking zu überwachen.

Eine weitere Option ist das Erstellen eines SSIS-Pakets mit N Anzahlen von Operatoren, um die SPs parallel aufzurufen

2
Pixelated

Sie könnten Powershell verwenden. Angenommen, Sie arbeiten mit SQL Server, könnten Sie Folgendes tun: (jetzt getestet und bereinigt)

#This script creates a number of connections (one per entry in $Commands) 
# to a SQL Server instance ($Server) and database ($DBName)
#Driver variables


#Set Initial collections and objects    
$Server= "(local)\sql2016cs" ; #Server to connect to
$DBName = "Test" ; #Database to connect to

$Commands = @()
$Commands += "EXEC sp_LogMe 'a'"
$Commands += "EXEC sp_LogMe 'b'"

#Loop through commands array, create script block for establishing SMO connection/query
#Start-Job for each script block
foreach ($sql in $Commands ) {

# All of that extra information after "Smo" tells it to load just v12 (for when you have multiple
#   versions of SQL installed.)  Note: V13 is 2016.
 $cmdstr [email protected]"
`Add-Type -AssemblyName "Microsoft.SqlServer.Smo,Version=$(13).0.0.0,Culture=neutral,PublicKeyToken=89845dcd8080cc91"
`[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
`$SqlConn = New-Object Microsoft.SqlServer.Management.Smo.Server ("$Server")
`$SqlConn.Databases["$DBName"].ExecuteNonQuery("$sql")
"@

#Uncomment the next like to print the command string for debugging
# $cmdstr
#Execute script block in jobs to run the command asyncronously
$cmd = [ScriptBlock]::Create($cmdstr)
Start-Job -ScriptBlock $cmd
}

Hinweis: Ich habe dies von etwas Ähnlichem übernommen, das ich hier getestet habe: https://sqlstudies.com/2016/02/24/powershell-script-to-create-multiple-sql-server-connections/

In diesem habe ich eine Schleife ausgeführt, um eine Reihe von Befehlen zu erstellen, die dasselbe tun. Dieses Skript verwendet den Skriptblock, um jeden Befehl asynchron auszuführen, jedoch mit unterschiedlichen tatsächlichen Befehlen. Zur Vereinfachung habe ich die Liste der Befehle, die Sie ausführen möchten, in ein Array eingefügt und das Array durchlaufen.

2
Kenneth Fisher

Ich benutze eine C # App mit Multithread Parallel.ForEach um sp mit verschiedenen Parametern aufzurufen. Haben Sie drei Abschnitte. Init, Body, localFinally

public void NearLinkParallelGeneration(avl_range avl_pending, DateTime dt_start_process)
    {
        var parallelOptions = new ParallelOptions
        {
            MaxDegreeOfParallelism = Environment.ProcessorCount + 2
        };

        // create the partition based on the input
        var partitions = Partitioner
                            .Create(
                                fromInclusive: avl_pending.begin,
                                toExclusive: avl_pending.end,
                                rangeSize: 100
                            )
                            .GetDynamicPartitions();

        Parallel.ForEach(
            source: partitions,
            parallelOptions: parallelOptions,
            localInit: () =>
            {
                NpgsqlConnection conn = new NpgsqlConnection(strConnection);
                NpgsqlCommand cmd = new NpgsqlCommand();
                try
                {
                    conn.Open();
                    cmd.Connection = conn;
                    cmd.CommandText = "SELECT * FROM avl_db.process_near_link(@begin, @end, @start_time);";
                    cmd.CommandType = CommandType.Text;

                    NpgsqlParameter p = new NpgsqlParameter("@begin", NpgsqlDbType.Bigint);
                    cmd.Parameters.Add(p);

                    p = new NpgsqlParameter("@end", NpgsqlDbType.Bigint);
                    cmd.Parameters.Add(p);

                    p = new NpgsqlParameter("@start_time", NpgsqlDbType.Timestamp);
                    p.Value = dt_start_process;
                    cmd.Parameters.Add(p);
                }
                catch (NpgsqlException ex)
                {
                    Console.WriteLine(ex.InnerException);
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.InnerException);
                }

                return new { Connection = conn, Command = cmd };
            },
            body: (source, state, local) =>
            {
                if (local.Connection.State == ConnectionState.Open)
                {
                    string strResult = String.Format("From: {0} - To: {1}", source.Item1, source.Item2);
                    Console.WriteLine(strResult);

                    try
                    {
                        local.Command.Parameters["@begin"].Value = source.Item1;
                        local.Command.Parameters["@end"].Value = source.Item2;
                        local.Command.ExecuteNonQuery();
                    }
                    catch (NpgsqlException ex)
                    {
                        Console.WriteLine(ex.InnerException);
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.InnerException);
                    }

                    //strResult = String.Format("DONE From: {0} - To: {1}", source.Item1, source.Item2);
                    //Console.WriteLine(strResult);

                }
                return local;
            },
            localFinally: local =>
            {
                local.Command?.Dispose();
                local.Connection?.Dispose();
            }
        );
    }
1

Sie können auch ForEach -Parallel in Powershell.

Das folgende Beispiel (aus meiner Frage Powershell führt gespeicherte Prozeduren parallel in der Datenbank aus ) führt alle gespeicherten Prozeduren in einer Datenbank aus:

Workflow TestRunParallelExecute
{
    $ServerName = "localhost"
    $DatabaseName = "testrun"
    $Procedure_Query = "select name from sys.procedures"
    $Procedure_List = (Invoke-Sqlcmd -Server $ServerName -Database $DatabaseName -Query $Procedure_Query)

    ForEach -Parallel ($Procedure in $Procedure_List.Name)
    {
         Invoke-Sqlcmd -Server $ServerName -Database $DatabaseName -Query $Procedure 
    }
}
TestRunParallelExecute
cls
1
user162241

Da dies mich an einen Anwendungsfall erinnert, den ich bei der Arbeit hatte, werde ich sagen, wie wir ihn lösen:

Zunächst glaube ich, wie bereits gesagt, dass es in SQL kein Unix "Nohup" -ähnliches gibt: eine Verbindung = eine Anweisung mit allem, was dazugehört (Sperren, Festschreiben, Fehler ...)

Wir finden unseren Weg mit dem kostenlosen ETL Talend, konfigurieren es für die Verbindung mit der Datenbank und führen eine Reihe von parallelen Jobs aus, die die gespeicherte Prozedur umschließen.

Wir haben die Komponente Iterate verwendet und so oft wie nötig eine Schleife ausgeführt, um die multi-threads Möglichkeit.

0
Blag