Laden...

Import dauert von Mal zu Mal deutlich länger

Erstellt von Stahli vor 9 Jahren Letzter Beitrag vor 9 Jahren 2.164 Views
Hinweis von herbivore vor 9 Jahren

Abgeteilt von Welchen Performance-Profiler?

S
Stahli Themenstarter:in
23 Beiträge seit 2014
vor 9 Jahren

Hallo nochmal,

ich habe mal noch eine grundsätzliche Frage.
Ich importiere mehrfach ca. 30.000 Datensätze.
Bei ersten Import werden die Datensätze einfach eingefügt und bei weiteren Importen werden diese dann auf Unterschiede geprüft und geloggt (in SubTabellen zur Haupttabelle).

Der erste Import geht fix. Dann dauert jeder Import ca. 20-30 Sekunden länger. (Jeder Import läuft in einer eigenen Transaktion.)

Ich muss mir das heute Abend nochmal im Detail anschauen, wodurch das genau kommt. Indizes auf die Suchspalten habe ich gesetzt.

Würdet Ihr die Verlangsamung als normals Verhalten bewerten oder einen Fehler meinerseits unterstellen.

BulkInserts habe ich noch nicht genutzt weil ich die Geschwindigkeit der ersten Imports für ausreichend hielt und noch keine Erfahrungen mit BulkInserts habe (werde ich mir aber auch heute Abend anschauen). Wenn es mit jedem Import langsamer wird muss ich doch nochmal Hand anlegen.
30434 Objekte neu, 25572 Objekte geändert, 0 Objekte unverändert. Dauer: 00:45
40 Objekte neu, 85 Objekte geändert, 30344 Objekte unverändert. Dauer: 00:47
78 Objekte neu, 84 Objekte geändert, 30376 Objekte unverändert. Dauer: 01:14
31 Objekte neu, 210 Objekte geändert, 30295 Objekte unverändert. Dauer: 01:39
39 Objekte neu, 322 Objekte geändert, 30209 Objekte unverändert. Dauer: 01:57
32 Objekte neu, 429 Objekte geändert, 30102 Objekte unverändert. Dauer: 02:21
58 Objekte neu, 434 Objekte geändert, 30127 Objekte unverändert. Dauer: 02:49
16 Objekte neu, 518 Objekte geändert, 30088 Objekte unverändert. Dauer: 03:03
92 Objekte neu, 536 Objekte geändert, 30079 Objekte unverändert. Dauer: 03:26
68 Objekte neu, 610 Objekte geändert, 30101 Objekte unverändert. Dauer: 03:42
72 Objekte neu, 532 Objekte geändert, 30233 Objekte unverändert. Dauer: 04:06
44 Objekte neu, 523 Objekte geändert, 30299 Objekte unverändert. Dauer: 04:27
23 Objekte neu, 549 Objekte geändert, 30308 Objekte unverändert. Dauer: 04:47

bye bye Delphi

W
955 Beiträge seit 2010
vor 9 Jahren

--- Fehler meinserseits, sry.

16.835 Beiträge seit 2008
vor 9 Jahren

Wie lädst Du vorhandene Elemente? Alle, oder einzeln? Serialisierung?
Wie vergleichst Du die Elemente? Musst Du für den Vergleich alles laden?

Meine Vermutung ist, dass Du alles lädst, alles einzeln.
Und dann geht natürlich die Kurve der Dauer deutlich und schnell nach oben.

4.221 Beiträge seit 2005
vor 9 Jahren

Werden dabei auch Indizierte Felder geändert ? (ein Update von Indizierten Feldern ist teuerer als ein Insert).

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

C
2.121 Beiträge seit 2010
vor 9 Jahren

Am ersten Import, bei dem sehr vieles neu erstellt und auch geändert wird, sieht man dass es schnell gehen kann.
Danach passiert kaum mehr was, aber es wird immer langsamer. Da scheint also wirklich was zu haken, normal ist das nicht.

Du sagst beim ersten Import gehts schnell, was macht den ersten aus? Ist nach Programmneustart auch ein "erster" Import wo es wieder schnell geht?
Versuche den Fehler durch solche Dinge einzugrenzen.

Ich importiere mehrfach ca. 30.000 Datensätze.

Dann steht da: 30434 Objekte neu, 25572 Objekte geändert
Macht schon über 56000 Objekte statt 30000. Stimmt da vielleicht noch was nicht? Könnte ja sein dass du wirklich nur 30000 Objekte übernehmen willst, aber durch irgendwelche Seiteneffekte blasen die sich auf und werden vervielfacht.

Wie läuft der Vergleich ab? Nutzt du Hilfstabellen dazu? Könnte es sein dass die nicht ganz geleert werden und dadurch immer mehr Arbeit entsteht?

S
Stahli Themenstarter:in
23 Beiträge seit 2014
vor 9 Jahren

Der Tipp von Programmierhans könnte vielleicht passen.
Ich habe wohl in SQL-Updates z.B. ein indiziertes Nr-Feld neu mit dem gleichen Wert überschrieben, vielleicht bremst das? Schaue ich mir nachher zu Hause genauer an.

Ich schlage immer pro Zeile aus der Importdatei (csv) die Records in den DB-Tabellen nach und prüfe auf Änderungen.
Eigentlich müsste es dann immer ähnlich schnell laufen wie im zweiten Durchgang.

Die 30T + 25T sind missverständlich.
Es werden einfach bei 25T von 30T neuen Records "Änderungs"-Logs eingetragen (also quasi Startwerte geloggt) und dort mit gezählt.
Die Zähler geben nur einen Überblick, wieviele Änderungen und neue Records es gab. Das kann zur Orientierung so bleiben.

Nach Programmneustart ist es auch langsam, wenn die DB schon gefüllt ist.
Vielleicht habe ich doch auch nur einen bestimmten Index vergessen?

Ich gebe bescheid, was ich finde.

bye bye Delphi

16.835 Beiträge seit 2008
vor 9 Jahren

Ich schlage immer pro Zeile aus der Importdatei (csv) die Records in den DB-Tabellen nach und prüfe auf Änderungen.
Eigentlich müsste es dann immer ähnlich schnell laufen wie im zweiten Durchgang.

Das ist die langsamste Variante, die man umsetzen kann.
Schneller ist >natürlich< eine Block-Verarbeitung, zB von 100 oder 1000 oder 10000 Elementen.

Du hast ja im anderen Thread bereits bemerkt, dass Blöcke oder in dem Fall Transactions deutlich performanter sind.

S
Stahli Themenstarter:in
23 Beiträge seit 2014
vor 9 Jahren

Haben wir uns missverstanden?
Ich lasse einen kompletten Import (30T Zeilen) jeweils in einer Transaktion laufen.

Dann schlage ich bei jeder Zeile immer per Selects in den Tabellen nach und veranlasse ggf. Inserts bzw. Updates.

... mal ein Auszug:

                        #region ImportCityPart
                        cmdSelectCityParts.Parameters["@CityId"].Value = CurrentCity;
                        cmdSelectCityParts.Parameters["@Nr"].Value = rCityPartNr;
                        reader = cmdSelectCityParts.ExecuteReader();
                        if (!reader.Read())
                        {
                            reader.Close();
                            cmdInsertCityParts.Parameters["@CityId"].Value = CurrentCity;
                            cmdInsertCityParts.Parameters["@Nr"].Value = rCityPartNr;
                            cmdInsertCityParts.Parameters["@Name"].Value = "#" + rCityPartNr;
                            lCityPartId = (int)cmdInsertCityParts.ExecuteScalar();
                        }
                        else
                        {
                            lCityPartId = Convert.ToInt32(reader["Id"]);
                            lCityPartUsed = Convert.ToBoolean(reader["Used"]);
                            reader.Close();
                            if (!lCityPartUsed)
                            {
                                cmdUpdateCityParts.Parameters["@CityId"].Value = CurrentCity;
                                cmdUpdateCityParts.Parameters["@Nr"].Value = rCityPartNr;
                                cmdUpdateCityParts.ExecuteNonQuery();
                            }
                        }
                        #endregion
                        
                        #region ImportStreet
                        cmdSelectStreets.Parameters["@CityId"].Value = CurrentCity;
                        cmdSelectStreets.Parameters["@Nr"].Value = rStreetNr;
                        reader = cmdSelectStreets.ExecuteReader();
                        if (!reader.Read())
                        {
                            reader.Close();
                            cmdInsertStreets.Parameters["@CityId"].Value = CurrentCity;
                            cmdInsertStreets.Parameters["@Nr"].Value = rStreetNr;
                            cmdInsertStreets.Parameters["@Name"].Value = rStreetName;
                            lStreetId = (int)cmdInsertStreets.ExecuteScalar();
                            lStreetName = rStreetName;
                        }
                        else
                        {
                            lStreetId = Convert.ToInt32(reader["Id"]);
                            lStreetName = reader["Name"].ToString();
                            lStreetUsed = Convert.ToBoolean(reader["Used"]);
                            reader.Close();
                            if (!lStreetUsed)
                            {
                                reader.Close();
                                cmdUpdateStreets.Parameters["@CityId"].Value = CurrentCity;
                                cmdUpdateStreets.Parameters["@Nr"].Value = rStreetNr;
                                cmdUpdateStreets.Parameters["@Name"].Value = rStreetName;
                                cmdUpdateStreets.ExecuteNonQuery();
                            }
                        }

                        cmdSelectCityParts_Streets.Parameters["@CityPartId"].Value = lCityPartId;
                        cmdSelectCityParts_Streets.Parameters["@StreetId"].Value = lStreetId;
                        reader = cmdSelectCityParts_Streets.ExecuteReader();
                        if (!reader.Read())
                        {
                            reader.Close();
                            cmdInsertCityParts_Streets.Parameters["@CityPartId"].Value = lCityPartId;
                            cmdInsertCityParts_Streets.Parameters["@StreetId"].Value = lStreetId;
                            cmdInsertCityParts_Streets.ExecuteNonQuery();
                        }
                        else
                        {
                            reader.Close();
                        }
                        #endregion

bye bye Delphi

16.835 Beiträge seit 2008
vor 9 Jahren

Korrekt. Du machst Select für Select.
Du kannst aber auch gleich 1?? relevante Elemente in einem Select abrufen. Spart schon mal einiges.
Schließlich wird die Anzahl der Verbindungen sowie die Anzahl der Queries und damit der Overhead kleiner.

Optional:
Und diese 100/1?? Elemente kann man dann sogar parallelisiert vergleichen.

S
Stahli Themenstarter:in
23 Beiträge seit 2014
vor 9 Jahren

Oh! (hier fehlt ein "rot-werd-Smily 😉 )

Ich habe in den SubTabellen zwar die Fremdschlüssel auf die Haupttabelle eingestellt, aber keinen expliziten Index auf das Feld. Dadurch wurden die späteren (häufigen) Suchen natürlich länger, je größer die Tabellen werden.

Entschuldigung für meine B....
30434 Objekte neu, 25572 Objekte geändert, 0 Objekte unverändert. Dauer: 00:20
40 Objekte neu, 85 Objekte geändert, 30344 Objekte unverändert. Dauer: 00:13
78 Objekte neu, 84 Objekte geändert, 30376 Objekte unverändert. Dauer: 00:14
31 Objekte neu, 210 Objekte geändert, 30295 Objekte unverändert. Dauer: 00:14
39 Objekte neu, 322 Objekte geändert, 30209 Objekte unverändert. Dauer: 00:14
32 Objekte neu, 429 Objekte geändert, 30102 Objekte unverändert. Dauer: 00:14
58 Objekte neu, 434 Objekte geändert, 30127 Objekte unverändert. Dauer: 00:15
16 Objekte neu, 518 Objekte geändert, 30088 Objekte unverändert. Dauer: 00:15
92 Objekte neu, 536 Objekte geändert, 30079 Objekte unverändert. Dauer: 00:15
68 Objekte neu, 610 Objekte geändert, 30101 Objekte unverändert. Dauer: 00:14
72 Objekte neu, 532 Objekte geändert, 30233 Objekte unverändert. Dauer: 00:15
44 Objekte neu, 523 Objekte geändert, 30299 Objekte unverändert. Dauer: 00:14
23 Objekte neu, 549 Objekte geändert, 30308 Objekte unverändert. Dauer: 00:15

Dass das so rennt hätte ich nie gedacht.

Danke Euch!

bye bye Delphi