Sehr langsame foreach Schleife

7

Ich arbeite an einer bestehenden Anwendung. Diese Anwendung liest Daten aus einer großen Datei und speichert sie nach einigen Berechnungen in einer anderen Tabelle.

Aber die Schleife, die das macht (siehe unten), benötigt eine sehr lange Zeit. Da die Datei manchmal 1.000 Datensätze enthält, dauert der gesamte Prozess Tage.

Kann ich diese foreach Schleife durch etwas anderes ersetzen? Ich habe versucht mit Parallel.ForEach und es hat geholfen. Ich bin neu in diesem Bereich und schätze Ihre Hilfe.

%Vor%

Nachdem ich die Antworten gelesen hatte, entfernte ich das Async und benutzte den Code wie folgt. Aber das hat die Performance nicht verbessert.

%Vor%     
user1110790 30.08.2012, 17:17
quelle

6 Antworten

7

Anstatt die sql-Verbindung so oft zu wiederholen, sollten Sie in Betracht ziehen, die gesamte Datenmenge aus dem SQL-Server zu extrahieren und die Daten über den Datensatz zu verarbeiten?

Bearbeiten: Beschlossen, weiter zu erklären, was ich meinte .. Sie können Folgendes tun, Pseudocode wie folgt

  1. Verwenden Sie ein select * und rufen Sie alle Informationen aus der Datenbank ab und speichern Sie sie in einer Liste des Klassen- oder Wörterbuchs .
  2. Machen Sie Ihre foreach (notieren Sie someRecord in someReport) und passen Sie die Bedingung wie üblich an.
Guo Hong Lim 30.08.2012 17:20
quelle
6

Schritt 1: Probieren Sie den Versuch asynchron aus. Es ist nicht richtig implementiert und du blockierst trotzdem. Führen Sie einfach die Prozedur aus und sehen Sie, ob das hilft.

Schritt 2: Verschieben Sie den SqlCommand außerhalb der Schleife und verwenden Sie ihn für jede Iteration erneut. Auf diese Weise entstehen keine Kosten für das Erstellen und Zerstören für jedes Element in der Schleife.

Warnung: Stellen Sie sicher, dass Sie Parameter, die Sie nicht von der vorherigen Iteration benötigen, zurücksetzen / löschen / löschen. Wir haben so etwas mit optionalen Parametern gemacht und hatten von der vorherigen Iteration "bluten-thru", weil wir Parameter, die wir nicht brauchten, nicht bereinigt haben!

    
n8wrl 30.08.2012 17:23
quelle
3

Dein größtes Problem ist, dass du das überbrückst:

%Vor%

Die gesamte Idee des asynchronen Modells besteht darin, dass der aufrufende Thread (derjenige, der diese Schleife ausführt) alle asynchronen Tasks mit der Begin-Methode startet, bevor er mit den Ergebnissen mit der End-Methode arbeitet. Wenn Sie Thread.Sleep () innerhalb Ihres Hauptaufruf-Threads verwenden, um darauf zu warten, dass ein asynchroner Vorgang abgeschlossen wird (wie Sie hier sind), tun Sie es falsch, und was schließlich geschieht, ist, dass jeder Befehl nacheinander ausgeführt wird , wird aufgerufen und dann gewartet, bevor der nächste startet.

Versuchen Sie stattdessen etwas wie folgt:

%Vor%     
KeithS 30.08.2012 17:39
quelle
1

In SQL am anderen Ende eines Schreibvorgangs ist eine (eine) Festplatte. Sie können selten schneller parallel schreiben. Tatsächlich verlangsamt es parallel dazu oft die Indexfragmentierung. Wenn Sie die Daten vor dem Laden nach primärem (gruppiertem) Schlüssel sortieren können. In einer großen Last sogar andere Schlüssel deaktivieren, laden Daten Rebuild-Schlüssel.

Nicht wirklich sicher, was im asynch passiert, aber sicher hat es nicht getan, was Sie erwartet haben, da es auf sich selbst gewartet hat.

%Vor%     
paparazzo 30.08.2012 17:41
quelle
1

Wie wir in den Kommentaren besprochen haben, könnte es effizienter sein, diese Daten im Speicher zu speichern und damit zu arbeiten.

Eine einfache Möglichkeit besteht darin, mit Entity Framework zu beginnen. Entity Framework generiert basierend auf Ihrem Datenbankschema automatisch die Klassen für Sie. Dann können Sie eine gespeicherte Prozedur importieren , die Ihre SELECT-Anweisung enthält. Der Grund, warum ich empfehle, ein gespeichertes Proc in EF zu importieren, ist, dass dieser Ansatz im Allgemeinen effizienter ist als Ihre Abfragen in LINQ gegen EF.

Führen Sie dann den gespeicherten Prozess aus und speichern Sie die Daten in einem List wie folgt ...

var data = db.MyStoredProc().ToList();

Dann kannst du mit dem data alles machen, was du willst. Oder wie bereits erwähnt, wenn Sie viele Nachschlagevorgänge für Primärschlüssel durchführen, dann verwenden Sie ToDictionary() so etwas ...

var data = db.MyStoredProc().ToDictionary(k => k.MyPrimaryKey);

In jedem Fall werden Sie zu diesem Zeitpunkt mit Ihrem data im Speicher arbeiten.

    
Steve Wortham 30.08.2012 21:40
quelle
0

Es scheint, dass die Ausführung Ihres SQL -Befehls bestimmte Ressourcen blockiert, und das hat den Grund dafür, dass Sie Async methods verwenden (meine Vermutung), erzwungen.

Wenn die Datenbank nicht verwendet wird, versuchen Sie einen exklusiven Zugriff darauf. Selbst dann, wenn es aufgrund der Komplexität des Datenmodells einige interne Transaktionen gibt, sollten Sie den Datenbankdesigner konsultieren.

    
Xaqron 30.08.2012 17:40
quelle

Tags und Links