Laden...

C#-Programm mit SQL-Zugriff beschleunigen

Erstellt von Gawan vor 17 Jahren Letzter Beitrag vor 16 Jahren 3.981 Views
G
Gawan Themenstarter:in
38 Beiträge seit 2005
vor 17 Jahren
C#-Programm mit SQL-Zugriff beschleunigen

Hallo zusammen,

ich hatte heute vor eine bestehende VisualBasic-Anwendung auf ASP-Basis etwas zu optimieren und die gleiche Funktionalität in C# nachzubauen.
Das ASP-File liest x Zeilen aus einem Textfile aus, generiert daraus INSERT-Strings für eine Datenbank und führt diese einen nach dem anderen aus (per ADO).

Ich habe die gleiche Funktionalität jetzt so einfach wie möglich nachgebaut, meine Lösung ist aber ca. 50% langsamer und das kann ich absolut nicht nachvollziehen.

Ich teste das Ganze mit 200.000 Datensätzen (=Zeilen im Textfile) und starte jedes INSERT-Statement einzeln mittels myCommand.ExecuteNonQuery();

Gibt es irgendeine Möglichkeit dieses Progremm entscheidend zu beschleunigen ??


using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {


DateTime d1 = DateTime.Now;
            
            StreamReader sr = new StreamReader("PRODPUCPC"); 
            
                String line;
            String mi="";

            string[] arrIP;

               SqlConnection myConnection = new SqlConnection("user id=sa;" +
                                       "password=***;server=localhost;" +
                                       "Trusted_Connection=yes;" +
                                       "database=LoDa; " +
                                       "connection timeout=30");
            try
            {
                myConnection.Open();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            


                SqlCommand myCommand = new SqlCommand("insert into ..." ,myConnection);



                for (int i = 0; i < 200000; i++)
                {
                    myCommand.ExecuteNonQuery();
                    line = sr.ReadLine();
                    arrIP = line.Split(' ');
                    for (int j = 0; j < arrIP.Length; j++)
                    {
                        mi.Insert(0, arrIP[j]);
                    }

                }

            try
            {
                myConnection.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            DateTime d2 = DateTime.Now;
            TimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks);
            Console.WriteLine(ts.Minutes+"    "+ts.Seconds + "   " + ts.Milliseconds);
            Console.ReadLine();

        }
    }
}

Ich lese in diesem Code noch nicht direkt aus dem Textfile, simuliere diesen Vorgang aber.

Danke
Gawan

T
512 Beiträge seit 2006
vor 17 Jahren

Du kannst eine ganze Menge rausholen, wenn du SqlParameter benutzt. Wenn du die richtig konfigurierst, d.h. Datentyp setzen, Länge setzen, und bei Numeric/Decimal Präzession setzen, dann kannst du die Prepare Funktion von SqlCommand aufrufen. Damit wird das ganze als eine Art Stored Procedure hinterlegt, und der SQL Server spart Zeit zum compilieren und optimieren.
Damit konnte ich eine ähnliche Anwendung um ein vielfaches beschleunigen.

Eine zweite Variante wäre alles in eine Datei zu schreiben, und dann BULK INSERT zu benutzen.

Eventuell könntest du auch mit zwei Threads etwas rausholen. Natürlich nicht in der Simulation.
Aber wenn ein Thread die Datei ließt, und ein anderer in die Datenbank schreibt, könnte eventuell die Rechenzeit besser genutzt werden.

e.f.q.

Aus Falschem folgt Beliebiges

F
10.010 Beiträge seit 2004
vor 17 Jahren

Und noch mehr kannst Du rausholen, wenn Du eine Transaction for der Schleife öffnest.
Sonst wird eine für jede einzelne Aktion gemacht, was unnötig Zeit kostet.

Aber nur mal so, dies braucht i.A. kein Mensch.

Wenn Du so viele Daten hast, benutzt man entweder Bulkcopy,
oder den neuen SyncService vo MS.

G
Gawan Themenstarter:in
38 Beiträge seit 2005
vor 17 Jahren

Schönen Dank für die Antworten !!!!

Ich hab jetzt die 200.000 execute.nonquery durch ein BulkCopy ersetzt und bin dadurch von ca. 200 Sekunden auf 12 Sekunden heruntergekommen 👍 👍 👍 👍

lG
Gawan

B
325 Beiträge seit 2005
vor 16 Jahren

Orientiere mich im Moment noch stark am Galileo openbook und habe das auch beim DB-Zugriff getan.
Habe den Fall, dass ein Datensatz mehrere "Unterwerte" haben kann. Im Openbook ist es beispielhaft mit Autoren und Büchern dargestellt. Hat ein Autor mehrere Bücher und ich frage dies auf dem "klassischen" Weg ab, erhalte ich ja Redundanz...
Als Lösung werden DataTables, DataRelations etc. aufgeführt.
Dazu werden aber immer alle Werte aus den entsprechenden Tabellen abgerufen. In meinem Fall ist es dann so, dass ich in den entsprechenden foreach-Schleifen noch einige If-Abfragen habe und nur, wenn alle erfolgreich passiert sind, der Datensatz auch wirklich gespeichert wird. Daher habe ich bisher noch jedes Abfrage hinbekommen und ich bilde mir auch ein, keine Redundanz zu haben.

Nun wurde mir jedoch empfohlen, parametrisierte Abfragen zu nutzen. Diese ergeben bei meinem bisherigen Ansatz ja keinen Sinn, da ich einfach beliebige "SELECT * FROM x" Abfragen mittels Relations kombiniere.

Ich habe nun also mit Hilfe von VS meine SQL-Abfragen "gebastelt".
Dabei kommen dann Monster mit 6 INNER JOINS heraus. Dennoch bilde ich mir ein, dass mein Programm damit schneller läuft, trotz Redundanz und noch ohne Parameter.

Kann das sein? Welchen Weg soll ich einschlagen?

Gelöschter Account
vor 16 Jahren

nun

wenn da ein inner join ist und du diese abfrage standardmäßig benutzt hast du wohl eine relation vergessen.

in der regel sind 6 inner joins noch nciht bedenklich aber vermeidbar.

B
325 Beiträge seit 2005
vor 16 Jahren

Bei der Lösung mit den Relations benutze ich kein JOIN, dies ist nur bei der zweiten Variante der Fall...
Das 6 INNER JOINS vermeidbar sind, habe ich ja selbst gesehen. Allerdings weiß ich nicht, ob 6 INNER JOINS Kindergarten sind bzw. das Abfragen aller Daten, wenn ich doch nur bestimmte will, Sinn der Sache ist.