Announcement

Collapse
No announcement yet.

sehr schneller Insert benötigt

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • sehr schneller Insert benötigt

    Hallo!

    ich hab mir ein tool in C# programmiert, dass daten auf unterschiedliche Weise in eine Datenbank einfügt.

    Die DB ist ein MSSQL Server 2005 Express. Die Connection läuft über eine ODBCConnection.

    es sind ungefähr 3000 Datensätze mit je 60 Werten.

    Als erstes hab ich versucht die Datensätze einzeln einzufügen. Also mit einem Insert. Klappt prima, aber ist ein bisschen langsam. Mehrere Messungen ergaben das die kürzeste Zeit 13 Sekunden waren.

    Dann hab ich es mit einem Paket von Datensätzen versucht. Also erst 2 Datensätze dann 3 und so weiter... Bei 2 und 3 datensätzen gleichzeitig lag der Beste wert auch bei ca. 13 Sekunden. Also keine Verbesserung.

    Dann versuchte ich die Daten in ein Dataset zu schreiben und über einen ODBCDataadapter mit hilfe des Update-befehls mit der Datenbank abzugleichen. Das hat jedes mal mehr als 1 Minute gedauert. Das ging nach hinten los.


    So, nun zu meiner Frage! Gibt es eine schnellere Methode die 3000 Datensätze in eine Datenbank zu schreiben? Oder was kann ich noch ausprobieren? Wie könnte der Code in ADO.NET aussehen? Hab noch nicht mit ADO gearbeitet.


    Vielen Dank im Voraus!

    Sebastian Schulz

  • #2
    Hi Sebastian,

    also es kommt ein bißchen darauf an, wieviel Zeit Du investieren willst und welches Ergebnis Du brauchst...

    Einfachster Ansatz wäre erstmal alle Insert-Befehle als eine Einheit auf die DB loszulassen, soll heissen:
    Code:
    SqlConnection Conn = new SqlConnection( [ConnectionString] );
    SqlCommand cmd = Conn.CreateCommand();
    cmd.CommandText = 
    "insert into Mytable values ( 1 )
    insert into Mytable values ( 2 )
    insert into Mytable values ( 3 ) ... "
    cmd.ExecuteNonQuery();
    Als nächstes Transaktionskontrolle:
    Code:
    SqlConnection conn = new SqlConnection( [ConnectionString] );
    SqlCommand cmd = conn.CreateCommand();
    SqlTransaction tran = cmd.Connection.BeginTransaction();
    cmd.Transaction = tran;
    ...
    inserts wie oben beschrieben durchführen
    ...
    tran.Commit
    Ansonsten gibt' s auch serverseitig noch einiges hier :
    http://msdn2.microsoft.com/de-de/library/ms175937.aspx

    HTH,
    Karsten

    P.S.: Habe den Code nur so aus dem Kopf aufgeschrieben, hoffe, dass alles so ungefähr stimmt

    Comment


    • #3
      1, Du verwendest .NET und greifst auf eine MS SQL Server DB zu. Da ist so ziemlich das schlechteste über den riesenumweg ODBC zu gehen. .NET hat direkte Zugriffs-Komponenten.

      2, Performanceverbesserungen bekommt man z.B. durch Verwendung von Prepared statements oder Stored Procedures. So alle paar ms ein Insert sollte kein Problem darstellen (Auch wenn man z.B. nur Win32 verwendet und kein .NET).

      Comment


      • #4
        Hallo Sebastian,

        ich hatte das Problem auch, aber ich habe es gelöst:
        Code:
                /// <summary>
                /// Ermöglicht das Massenkopieren von Daten aus einer DataTable in eine Tabelle
                /// auf SQL-Server mit einer sehr hohen Performance (Table[0] des DataSet)
                /// Es wird DataSet und nicht DataTable wegen Serialisierung benutzt!
                /// !!! ACHTUNG !!! Es ist dafür notwendig dem ApplicationUser (Webservice) die 
                /// benötigten Schreibrechte für die entsperechende Tabelle zu geben.
                /// </summary>
                /// <param name="ds">DataSet(Table[0]) mit identischer Struktur zur Tabelle auf SQL-Server</param>
                /// <param name="SQLServerTableName">Name der Tabelle auf SQL-Server für die die Daten bestimmt sind</param>
                public void WriteDataBcp(DataSet ds, string SQLServerTableName)
                {
                    SqlConnection aConn = GetConn();
                    try
                    {
                        aConn.Open();
                        SqlBulkCopy bcp = new SqlBulkCopy(aConn);
                        bcp.DestinationTableName = SQLServerTableName;
                        bcp.BulkCopyTimeout = 60;
                        bcp.WriteToServer(ds.Tables[0]);
                    }
                    finally
                    {
                        aConn.Close();
                    }
                }
        Probier es aus - ich sage nur - BOOSTER!

        Gruß
        Olaf

        Comment


        • #5
          das bulkcopy funktioniert super ^^
          nichtmal 1 sekunde für ein DS mit 3000 Datensätzen. :-)

          Aber das hinzufügen der Zeilen dauert zu lange! Ich brauche glatt 50 Sekunden für das erstellen der Rows.

          Ich mach das mit table.rows.add(row)!

          Gibt es eine schnellere Möglichkeit eine zeile zu einer Datatable hinzuzufügen?

          Gruß
          Sebastian

          Comment


          • #6
            Hallo,

            woher stammen die über SqlBulkCopy einzufügenden Daten? Aus einer CSV-Datei, einer anderen Datenbank...? Ist während des Hinzufügens der Daten eine Datenbindung an die Benutzeroberfläche (DataGrid, DataGridView) aktiv?

            Comment


            • #7
              Die Daten stammen aus Dateien, die Informationen enthalten. In diesem Fall sind es 3000 txt-Dateien, die ich erstmal auslese und dann die Informationen in die DataTable im DataSet einzufügen.

              Leider dauert das einfügen einer neuen Zeile in einer DataTable sehr sehr lange. Es ist fast 4 mal so langsam als wenn ich die Daten direkt per Insert-Befehl in die Datenbank einfüge.

              Ich hab jetzt eine ganz kuriose Möglichkeit gefunden, aber die ist nicht so sauber (find ich). Ich erstelle mir einen DataGridView und erstelle mir mit

              Code:
              DataGridView.Rows.Insert(0,<Anzahl der Datensätze>)
              die benötigten Zeilen. Dann füge ich in dieses DataGridView die ganzen Daten ein.
              Danach geh ich einmal über den kompletten DataGridView und erstelle mir für jede Zeile eine Zeile in der DataTable. Dann geh ich wieder über jede Zeile und füge die Daten in die DataTable ein.

              Dieser Code benötigt für das Auslesen der Dateien und das Einfügen der Daten in die DataTable und das anschließende Senden an die Datenbank mittels BulkCopy 4,4 Sekunden. Und das ist fast 3 mal so schnell, wie mein bisheriger Code.

              Was meint Ihr? Kann man da noch was beschleunigen?

              Gruß
              Sebastian

              PS.: in der benutzeroberfläche kann man nix von den Daten sehen.

              Comment


              • #8
                Hallo,

                wenn die Daten aus TXT-Dateien stammen, kann der OleDbAdapter/OdbcAdapter den kompletten Dateiinhalt mit einem Fill-Aufruf in das DataSet laden.

                Ich hab jetzt eine ganz kuriose Möglichkeit gefunden,...
                Wenn der Weg DataGridView+Add schneller ist als der einzelne Add-Aufruf, kann das Problem nicht an dem Add-Aufruf liegen. Wie sieht ein Minimal-Beispiel aus, mit dem dieser Effekt reproduziert werden kann? Wie werden die einzelnen Felder aus der TXT-"Datensatz" ausgewertet und beim Add-Aufruf übergeben?

                Comment


                • #9
                  Die TXT-Dateien müssen erst ausgewertet und die Daten dementsprechend angepasst oder verändert werden. Erst danach, dürfen sie in die DB.

                  Ich hab das jetzt mal anders gemacht:

                  Code:
                  for (int i = 1;i<=<Anzahl der Datensätze>;i++)
                  {
                     currentTable.rows.add();
                  }
                  Erst danach werden die Daten in die DataTable geschrieben.
                  Ist um 3/10 Sekunden schneller. *g*

                  Davor hatte ich das so gemacht: (Der langsame Code)

                  Code:
                  DataRow CurrentRow;
                  foreach (String FileName in Files)
                  {
                  CurrentRow  = currentTable.NewRow();
                  <Auswertung der Datei>
                  <CurrentRow füllen>
                  currentTable.Rows.Add(CurrentRow);
                  }
                  Zuletzt editiert von tipsybroom; 20.11.2007, 16:03.

                  Comment

                  Working...
                  X