Performante Lösung zum Speichern von vielen Datensätzen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Performante Lösung zum Speichern von vielen Datensätzen

    Hallo,

    nachdem ich ja in letzter Zeit nicht mehr online war, hab ich mal wieder eine kleine Frage:

    Und zwar hab ich ziemlich viele Datensätze, und es mag User meines Programms geben, die sogar noch mehr haben. Es geht um einige tausend. Diese muss ich in irgendeiner Weise beim Beenden des Programms abspeichern, was ich bisher mit JSON getan habe.

    Das Serialisieren der Daten ist aber viiiell zu langsam, ich rede hier von, ich habs nicht gemessen, aber das sind gut und gerne 30 Sekunden, wenn nicht mehr. Gibts da vielleicht ne performantere Lösung, ich habe da z. B. an SQLite gedacht, jedenfalls ist mir das mal zu Ohren gekommen.

    Und wie würde das genau funktionieren?

    Freu mich auf Eure Antworten!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Da stimmt wirklich was nicht. Ich habe auch hunderte Datensatzpakete in einem Datensatz. Ich serialisiere auch zu JSON, dann noch verschlüsseln und komprimieren und dann zum Server. Das alles ist in max. 1 Sekunde erledigt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Da stimmt wirklich was nicht.


    Echt? Da bin ich erstmal froh, dass das wahrscheinlich nen anderen Grund hat...

    VB1963 schrieb:

    Wohin werden diese Daten gespeichert auf PC-Platte, irgendwo über ein Netzwerk oder gar über I-Net?


    Die Daten werden auf SSD gespeichert, aber das scheint nicht das Problem zu sein. Habs grad nochmal mit nem Haltepunkt versucht, es ist definitiv das Serialisieren selbst, nicht das Speichern:

    VB.NET-Quellcode

    1. Dim ZuSpeicherndeDTB As String = JsonConvert.SerializeObject(InhaltGesamt) 'diese 'Zeile dauert so lang
    2. System.IO.File.WriteAllText(Arbeitsverzeichnis & "\database\musicdata.dtb", ZuSpeicherndeDTB)


    Habs nochmal grad mit nem Einzelschritt versucht, da komm ich auf runde 13 Sekunden. Das ist zwar besser als ich es in Erinnerung hatte bzw. als es mir vorkam, aber immer noch zu langsam...

    InhaltGesamt is eine ObservableCollection mit einer Klasse mit diesen Eigenschaften. Es sind genau 5486 Datensätze.

    -12 Strings
    -2 Integer
    -1 TimeSpan
    -3 Boolean
    -1 weitere OC mit:
    _____-1 String
    _____-1 Timespan
    _____-1 Integer
    _____-1 weitere OC mit:
    __________-2 Strings
    __________-1 SolidColorBrush

    Die "weiteren OCs" sind dabei jetzt wie ich es getestet hab, leer.

    Ich hab einen Prozessor mit 4x 3.3 GHz

    Was meint ihr dazu?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    @kafffee Mach doch mal ein Benchmark-Testprogramm, wo Du n Random Datensätze erzeugst, speicherst und liest.
    Mach Dir ein paar Stopwatch-Instanzen, stoppe die Zeit an kritischen Stellen und gib sie aus.
    Das Projekt zippst Du und hängst es an und wir können das unter beliebigen Bedingungen testen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    Dat is doch mal ne Ansage :)

    Wie gesagt, das Speichern läuft wie am Schnürchen, das Deserialisieren Auch. Nur das Serialisieren dauert so lang...

    Also ich werd einfach mal die Datei mit dem Originaldatensatz nehmen die dann deserialisieren und wieder serialisieren und das Ganze stoppen.

    Bis später :)

    Hier das Benchmarkprogramm. Ich hoffe, ich hab nicht zu viele Dateien/Ordner aus dem ZIP gelöscht. Den Ordner mit dem JSON Nugetpaket hab ich komplett rausgenommen. Die dtb-Datei müsst ihr in den bin/Debug-Ordner kopieren.

    Merkwürdigerweise, mit der selben Datei wie in meinem Hauptprojekt, alles unter 1 Sekunde...auch bei mir

    Der einzige Unterschied:

    In der Datei MP3FileInfoVM ganz unten hab ich die Klasse ColorInfo und alle Verweise darauf auskommentiert, weil die natürlich in einem Konsolenprogramm nicht funktioniert hat.

    Was schlagt ihr vor?

    Vielleicht mal noch ein Testprojekt in WPF?

    Oder gibt's irgendwelche Debugging Tools, die ich noch nicht kenne, die mir anzeigen welche Funktion soviel Rechenleistung verschlingt?
    Was ich mit Sicherheit sagen kann, es liegt an der Zahl der Datensätze, weil wenn ich das Ganze nur mit sagen wir 100 Datensätzen mach geht es dementsprechend schneller...

    @VB1963

    Ich lass dein Vorschlag erstmal aus, es scheint ja nicht daran zu liegen...
    Dateien
    • JSONBenchmark.zip

      (11,89 kB, 672 mal heruntergeladen, zuletzt: )
    • musicdata.zip

      (186,58 kB, 260 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „kafffee“ ()

    folgende Ausgabe:

    Quellcode

    1. Benchmark wird ausgeführt...
    2. Deserialisieren: 873 Millisekunden
    3. Serialisieren: 79 Millisekunden
    Ich find das für ein 2,7MB-File nicht so unerträglich schlecht...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()


    Das hier ist schoma sehr böse:

    VB.NET-Quellcode

    1. sFile = "..\..\musicdata.json"
    2. InhaltGesamt = JsonConvert.DeserializeObject(Of ObservableCollection(Of MP3FileInfoVM))(File.ReadAllText(sFile))
    Da wird ein String mit Länge > 2Mio Zeichen erstellt.
    Verwende Streams und Reader, dann werden Dateien stückweise gelesen und verarbeitet, und belegen keine so Riesen-Blöcke.

    VB.NET-Quellcode

    1. Dim ser = New JsonSerializer()
    2. Using rd = New StreamReader(sFile), jrd = New JsonTextReader(rd)
    3. InhaltGesamt = ser.Deserialize(Of ObservableCollection(Of MP3FileInfoVM))(jrd)
    4. End Using

    (Ansonsten bin ich recht verzweifelt über deinen unleserlichen Codier-Stil, aber dem willst du wohl nicht abhelfen)

    ErfinderDesRades schrieb:

    Verwende Streams und Reader, dann werden Dateien stückweise gelesen und verarbeitet, und belegen keine so Riesen-Blöcke.


    Alles klar, man lernt nie aus :)

    ErfinderDesRades schrieb:

    (Ansonsten bin ich recht verzweifelt über deinen unleserlichen Codier-Stil, aber dem willst du wohl nicht abhelfen)

    Ah sry, normalerweise wenn ich ein Testprogramm mache oder nen komplizierteren Code poste, nehm ich dann mal auch dementsprechende Variablennamen...
    Hatte ich jetzt glatt vergessen... Also: Sry hierfür

    Hab das mal probiert in meinem Hauptprojekt, geht auch nicht merklich schneller...Wie gesagt es scheint am Serialisieren selbst zu liegen, nicht am Speichern...

    VB.NET-Quellcode

    1. Dim ser = New JsonSerializer()
    2. Using sw = New System.IO.StreamWriter(Arbeitsverzeichnis & "\database\musicdata.dtb") ', jrd = New JsonTextWriter(sw)
    3. ser.Serialize(sw, InhaltGesamt)
    4. End Using


    Hab mal auf dieses Diagnosetool mit der CPU-Auslastung geachtet, das ist wenn das Programm "idle" ist, nahe Null, und wenn ich das Speichern direkt vom dem Beenden des Programms anstosse steigt es auf ca. 30%...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Ich hab das ganze drei Mal gemacht. Wenn die Daten erest im Cache liegen, geht es erheblich schneller:


    Und: @kafffee

    VB.NET-Quellcode

    1. Option Strict On ' im Quelltext

    Du hast die empfohlenen Einstellungen nicht umgesetzt. :/
    Visual Studio – Empfohlene Einstellungen
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    Okay ja das ist deutlich zu sehen. Ich hab das "schwerwiegende" Problem aber beim Serialisieren, nicht beim Deserialisieren.

    Vielleicht ein WPF-Problem? Oder mal probieren explizit vom MainThread aufzurufen?

    Ich kann echt nur raten.

    Achja genau, vielleicht tuts was zur Sache: Aufgrund der langen Wartezeit beim Serialisieren hatte ich vor einiger Zeit auch versucht, vor dem Serialisieren eine selbst gebaute MessageBox anzuzeigen, die den Nutzer auf dieses Manko hinweist. Die wurde einfach wie wenn nichts wäre einfach nicht angezeigt. Kein Fehler, gar nix. Und die MessageBox funktioniert an anderer Stelle auch tadellos...

    Was ich auch probiert hab, das Serialisieren auch mal von einem Buttonklick anzustoßen, aber kein Erfolg...

    PS: Okay, ich stell Option Strict auf "on".

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „kafffee“ ()

    Wenn du selbst feststellst, dass dein Beispielprojekt, das Problem nicht repliziert, was sollen wir dann damit anfangen?

    Aber wo du schreibst WPF und ich sehe du belädst da ein ObservableCollection:
    Ich denke diese OC ist währenddessen aktiv angebunden und aktualisiert die Ansicht munter bei jedem Datensatz der eingesaugt wird. Jo und das 5000 mal machen das dauert.

    Wenn man Daten aus der Datenbank in eine DataTable holt, das an ein DGV gebunden ist, dauert das auch ewig (wenn da Formate bei automatisiert angepasst werden), trennt man das Binding während des Ladevorgangs kurzzeitig, ist alles fein.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    kafffee schrieb:

    Hab das mal probiert in meinem Hauptprojekt, geht auch nicht merklich schneller...Wie gesagt es scheint am Serialisieren selbst zu liegen, nicht am Speichern...
    nanu? Mein gepostetes Beispiel ging doch auch für Serialisieren, und nicht für deserialisieren.
    Also probiers bitte nochmal mit wie ich gepostet habe.

    Aber trotzdem gut möglich, dass der Reader-Einsatz nix bringt.
    Und dennoch würde ich das mit dem Reader empfehlen - das tut man einfach nicht, mit Strings der Länge 2Mio zu arbeiten.

    Haudruferzappeltnoch schrieb:

    trennt man das Binding während des Ladevorgangs kurzzeitig, ist alles fein.


    Das bestätigt meine Ahnung :)

    Aber kannst du mir auch sagen wie das geht? Ist nämlich eine MVVM-Application und ich hab nur das hier gefunden, das mag bei Code Behind richtig sein, aber wüsste nicht wie ich das vom ViewModel aus machen soll...:
    learn.microsoft.com/en-us/dotn…w=netframeworkdesktop-4.8

    @ErfinderDesRades

    Ich vergess dich nicht, ich geh jetz bloss erstmal der Spur von @Haudruferzappeltnoch nach, das klingt mir erstmal schlüssig...
    naja, nur mässig schlüssig. Während der Deserialisierung kann die OC an nix gebunden sein, weil sie wird da ja erst noch erstellt.

    Aber du kannst eine Messung einbauen in dein Echt - Code. Nämlich miss von vor Deserialisierung bis nach Deserialisierung - aber vor Zuweisung der OC an eine datengebundene Property.
    Das sollte so flott gehen wie im Testprojekt.
    Hm, ich bin was WPF angeht auch ein Neuling. Könnte mir vorstellen, dass das mit INotifyPropertyChanged-Events zu tun hat. Aber ist alles ein Schuss ins Blaue.
    Tatsächlich befülle ich bei mir eine ObservableCollection aus einer Datenbank, mit handgebautem DataAdapter. Das geht ganz gut, bei mir finden sich aber fast keine solchen Events, da ich die offenbar nicht benötige für das was ich tue.

    Wenn du da mal Teile aus dem Code zeigst, können die Experten da bestimmt was zu sagen. Und Fakt ist auch, dass dein Beispielprojekt kein WPF/MVVM war. Also mehr als raten kann hier keiner, würde ich sagen.
    @ErfinderDesRades

    Nochmal ums klarzustellen:
    -Deserialisieren -> kein Problem
    -Serialisieren -> Big Problem

    Also hab ich jetzt mal noch ein zweites Testprojekt gemacht. Diesmal in MVVM und siehe da, ich komm wieder auf meine 13 Sekunden, und zwar egal ob das Binding mit dem DataGrid besteht oder nicht...

    Das macht das Ganze jetzt ja auch nicht weniger komisch, oder?

    Probierts aus, ich bin mit meinem Latein da echt am Ende...: Code habt ihr dann ja :)
    Dateien