Autor Beitrag
mats74
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 189
Erhaltene Danke: 26

Win 10
VS 2017/19, C++, C#
BeitragVerfasst: Mi 21.11.12 11:56 
Hallo zusammen

Meine Aufgabe:
- Daten aus bestehenden XML-Dateien in bestehende Datensätze in SQL-Tabellen übernehmen
- Die Tabellen haben Foreign-Key Schlüssel, dadurch können die ID's der zu ersetzenden Datensätze nicht geändert werden
(also keine DELETE und INSERT-Anweisung möglich)

Folgender Code funktioniert, wird aber nach ca. 1000 eingetragenen Datensätzen extrem, massiv und unerträglich langsam :P :
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
// Bestehende Zeilen updaten
foreach (XmlNode _xmlnode in _xmlnodelist1)
{
    // Array der bestehenden ID's beachten
    for (int ii = 0; ii < ia_temp_wert.Length; ii++)
    {
        // Bestehende Zeile updaten
        if (Convert.ToInt32(_xmldocument.GetElementsByTagName("IRGENDETWAS").Item(i).InnerText) == ii)
        {
            befehl.CommandText = "UPDATE MEINETABELLE SET "
                               + "MEINESPALTE = '" + Convert.ToString(_xmldocument.GetElementsByTagName("IRGENDETWAS").Item(i).InnerText) + "',"
                               + "WHERE MEINEID = " + Convert.ToInt32(_xmldocument.GetElementsByTagName("ANDEREID").Item(i).InnerText) + ";";
            befehl.ExecuteNonQuery();
            break;
        }
        else
        {
        }
    }

    // Counter erhoehen
    i++;
}


Den Zeitverlust vermute ich im Query, das wahrscheinlich bei jedem Dateneintrag neu geparst wird.
Habe aber keine Ahnung, wie ich dies zu vermeiden habe.

Wie kann ich die Performance meines Imports erhöhen (damit meine Wenigkeit nicht in Dauerschlaf verfällt :wink: )?
Welche Importmöglichkeiten sind sonst noch zu prüfen?

Ich habe noch weiter Tabellen zu updaten, die mehr als 50000 Datensätze beinhalten, somit eine Wartezeit von über 10 h bewirken.
Muss definitiv auch schneller zu erstellen sein.

Danke für eure Hilfe.

_________________
Gruss
mats74
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 21.11.12 13:04 
Zitat:
Den Zeitverlust vermute ich im Query, das wahrscheinlich bei jedem Dateneintrag neu geparst wird.


Eher nicht. Der SQL Server(oder vergleichbare andere Datenbanken) ist eigentlich schlau genug zu erkennen das er dieses Abfragemuster kurz vorher schon mal hatte und wird denn Ausführungsplan wiederverwenden. Davon abgesehen sollte der Ausführungsplan bei einem simplen update auch ziemlich simpel sein und nicht wirklich Zeitkosten den zu ermitteln. Um sicherzugehen das das passiert und weil es eh Best Practice ist benutze Parameter für deinen Command und keine Stringzusammenwürfelei. Dann wird der Ausführungsplan garantiert wiederverwendet.

Was da langsam ist - die Query, die 1000 Ping Pong zwischen Programm und DB, die Authentifizierung bei jedem Aufruf etc. - solltest du mit entsprechenden Tools überprüfen. Also den Profiler vom SQL Server(bzw. die Entsprechung für dein Datenbankmodel) oder dem PerformanceMonitor von Windows.

Für diesen Beitrag haben gedankt: mats74
mats74 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 189
Erhaltene Danke: 26

Win 10
VS 2017/19, C++, C#
BeitragVerfasst: Mi 21.11.12 16:16 
Hallo Ralf

Vielen Dank für den Tip der parametrisierung der SQL-Statements.
Daran habe ich nicht mehr gedacht.
Das hat eine starke Verbesserung der Performance gegenüber einer Zuweisung eines (gebastelten :wink: ) Strings gebracht.
Der Ausführungsplan wurde wiederverwendet.

Die eigentliche Bremse war die For-Schleife.
Die habe ich dadurch eliminiert, dass ich die betreffenden Tabellen vorgängig entsprechend ergänzt und verändert habe.

Der erfolgreiche Code sieht nun folgendermassen aus:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
// SQL-Statement Text erstellen
string text = "UPDATE MEINETABELLE SET "
              + "MEINESPALTE = @anderespalte,"
              + "WHERE MEINEID = @andere_id;";

// Bestehende Zeilen updaten
foreach (XmlNode _xmlnode in _xmlnodelist1)
{
    befehl = new SqlCommand(text, verbindung);
    // Parameter hinzufügen und Werte übergeben
    befehl.Parameters.AddWithValue("@anderespalte", Convert.ToString(_xmldocument.GetElementsByTagName("ANDERESPALTE").Item(i).InnerText));
    befehl.Parameters.AddWithValue("@andere_id", Convert.ToString(_xmldocument.GetElementsByTagName("ANDEREID").Item(i).InnerText));
    befehl.ExecuteNonQuery();

    // Counter erhoehen
    i++;
}


Mit dieser Struktur beträgt die Einfügezeit pro Zeile ca. 1/100s pro Datensatz.
Somit auch bei grossen Tabellen Aufgabe gelöst.

_________________
Gruss
mats74