Laden...

Datenbank-Importvorgang wird langsamer

Erstellt von mcpd vor 11 Jahren Letzter Beitrag vor 11 Jahren 2.347 Views
M
mcpd Themenstarter:in
174 Beiträge seit 2009
vor 11 Jahren
Datenbank-Importvorgang wird langsamer

Hallo Leute,

ich habe folgendes Problem. Ich lese aus einem Verzeichnis ca. 15000 XML-Dateien aus und schreibe deren Inhalt in eine Datenbank. Da es ein sehr zeitaufwendiger Vorgang ist, setzte ich den BackGroundWorker ein. Das funktioniert soweit ganz gut, außer das nach ca. 2000 Dateien der Importprozess immer langsamer wird. Woran kann das liegen?

Mfg
mcpd

6.911 Beiträge seit 2009
vor 11 Jahren

Hallo mcpd,

Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 5, aber ich tippe auf den GC. Um genaueres zu sagen, verwende einen Profile.

Gib nicht mehr benötigte Objekte frei.
Wie importierst du in die DB? Per O/R-Mapper? Dann schau dass nicht alles in einem "riesen" Kontext kommt (sonst schlägt auch wieder der GC zu).

Wenn du den Importvorgang parallelisieren kannst, so könntest du mit Paralle.Foreach arbeiten. Dort gibt es eine Überladung (ich denke die 13.) mit der mittels localinit und localfinally eine Instanz des O/R-Mapper-Contextes pro Thread erstellt werden kann. Damit könntest du das Problem schon minimieren.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

P
40 Beiträge seit 2011
vor 11 Jahren

Wird er nur langsamer oder stürzt er dann (nach weiteren 4000) ab?
Gibst du alle Resourcen wieder frei oder behältst du alle Objekte in irgendeiner Art und Weise?

M
mcpd Themenstarter:in
174 Beiträge seit 2009
vor 11 Jahren

Hallo,

Danke für Eure Antwort. Für den Import in die DB benutze ich typisierte DataSets. Die einzelnen TableAdapter Objekte rufe ich mit "using" auf. Dann ist doch eine Freigabe der Objekte gewährleistet. Oder? Manchmal erhalte ich eine Meldung vom DB-Server, dass der Timeout abgelaufen ist.

ich füge mal bischen Code hinzu.


/// <summary>
        /// Die XML Dateien werden importiert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void btnStartImport_Click(object sender, EventArgs e)
        {
            // BUTTON
            btnStartImport.Enabled = false;
            btnCancelImport.Enabled = true;

            // Start des asynchronen Vorgangs            
            bgwImport.RunWorkerAsync();            
        }

        /// <summary>
        /// Arbeitsthread gibt einen Fortschritt an.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void bgwImport_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Fortschritt zuweisen
            this.pgbStatus.Value = e.ProgressPercentage;
        }

        /// <summary>
        /// Der Worker wurde beendet (erfolgreich, nicht erfolgreich, abgebrochen).
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void bgwImport_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Prüfen auf Error
            if (e.Error != null)
            {
                // Error anzeigen
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                // Message anzeigen
                MessageBox.Show("Vorgang durch Benutzer abgebrochen.");
            }
            else
            {
                // Message anzeigen
                MessageBox.Show("Import-Vorgang abgeschlossen.");
            }
        }

        /// <summary>
        /// Vorgang in einem anderen Thread ausführen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void bgwImport_DoWork(object sender, DoWorkEventArgs e)
        {
            // Methodenaufruf
            e.Result = ImportXmlFilesHelper(bgwImport, e);
        }
        #endregion

        #region Methods
        /// <summary>
        /// Die Helpermethode bereitet das Importieren die XML-Dateien vor.
        /// </summary>
        /// <param name="p"></param>
        /// <param name="worker"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        private object ImportXmlFilesHelper(BackgroundWorker worker, DoWorkEventArgs e)
        {
            // List auslesen
            foreach (string fileName in this.xmlFileNames)
            {
                // Methodenaufruf
                ImportXml(fileName);
            }           

            return null;
        }

        private void ImportXml(string fileName)
        {
            // Objekt erstellen
            this.importXmlToSql = new ImportXmlToSql();

            // Methodenaufruf
            importXmlToSql.ImportXmlData_ToSql(fileName);

            // Delegate erstellen und Methodenübergabe
            ImportDisplayFileNamesCallback displayFileNames = new ImportDisplayFileNamesCallback(ImportAndDisplayFileNamesInListView);

            // Ausführen
            this.Invoke(displayFileNames, new object[] { fileName, this.bgwImport });
        }

        /// <summary>
        /// Die XML Dateien werden importiert.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="worker"></param>
        private void ImportAndDisplayFileNamesInListView(string fileName, BackgroundWorker worker)
        {
            // INT
            int percent = xmlFileNames.Count / 100;
            this.fileName = fileName;

            // um "1" erhöhen
            this.count++;

            // Fileane anzeigen
            lblFileName.Text = fileName;

            // Info anzeigen
            lblFile.Text = String.Format("Datei: {0} von {1}", count, this.xmlFileNames.Count);

            // Fortschritt anzeigen
            lblCount.Text = String.Format("Fortschritt: {0}%", Convert.ToString(this.count / percent));

            // ProgessChanged Event auslösen
            bgwImport.ReportProgress(this.count / percent);
        }

Vielleicht nützt das was.

Mfg
mcpd

F
10.010 Beiträge seit 2004
vor 11 Jahren

Typisierte DataSets sind für so etwas unnötig.
Und wenn du bei den DataAdaptern die Transaction vergessen hast, sind die wirklich sehr langsam.

SqlBulkCopy.WriteToServer-Methode
Wäre hier deutlich schneller.

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo mcpd,

ohne dass ich mir den Code angeschaut habe, klingt die Symptombeschreibung grundsätzlich nach Schlemiel the Painter's algorithm oder technischer ausgedrückt, nach quadratischem Aufwand, siehe dazu auch Warum haben WinForms, DataGridView & LINQ eine gute Performance?

herbivore

3.825 Beiträge seit 2006
vor 11 Jahren

Hallo mcpd,

ich muss auch öfter mal viele Datensätze importieren (mehrere Tausend bis Millionen).

Mit DataSet einzeln hat das in einem Testfall 36 h gedauert.

Bulkcopy des SQL-Servers : 7 min.

Alle Daten in ein Dataset und dann auf einmal einfügen : 6 h

Dabei teile ich die Daten so auf dass es max. 500 MB im Hauptspeicher belegt.

Probier mal alle oder mehrere Zeilen ins Dataset und dann einfügen.

Ob das Dataset typisiert ist oder nicht sollte keine Rolle spielen.

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

476 Beiträge seit 2004
vor 11 Jahren

Hallo mcpd,

das kann viele Ursachen haben. Ich würde zunächst mit Profilern arbeiten und sowohl den Code als auch die Datenbank untersuchen bis du den Farbeimer von Schlemiel gefunden hast.

Welches DBMS nutzt du denn?
Wie komplex sind die XML-Dateien?
Wächst der Hauptspeicherverbrauch kontinuierlich ?

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de