Große Datenmengen aus DB laden

  • C#

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Kasi.

    Große Datenmengen aus DB laden

    Moinsen,

    ich habe eine Anwendung, bei der ich große Datenmengen (mehrere tausend Datensätze) von einer DB lade und in einen TreeView bzw. ein DataGridView eintragen will. Das dauert eine wenig und ist auch nicht schlimm.

    Ich kriege nur grad nicht die Kurve, wo genau im Code ich die Daten holen soll. Lade ich die Daten im Konstruktor des Fensters, dann wird dieses erst wirklich sichtbar, wenn das Laden und Sortiere der Daten abgeschlossen ist. Auch möchte ich einen Fortschrittsbalken anzeigen. Das Laden und Sortieren muss also asynchron passieren aber nicht im Konstruktor.

    Wie/Wo kriegt man es hin, dass der Nutzer einen Menupunkt auswählt, sich das Fenster öffnet und den noch nicht gefüllten Teil (DataGRidView bzw. TreeView) anzeigt aber dennoch automatisch Daten im Hintergrund lädt und dann in die Strukturen einfügt?

    Gruß

    MQ

    PS: Ich verwende das Entity Framework zusammen mit dem SQL Server in einer WinForms-Anwendung.
    Daten-Lade-Performance-Probleme liegen zu 90% am GUI - nicht am Data-Access.

    Schreib mal eine TestMethode in void Main(), die die Daten lädt, bevor irgendein Form überhaupt nur erwähnt wird. Und miss die Zeit.
    Und poste die Methode.

    Also sowas:

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Windows.Forms;
    5. namespace _Template {
    6. static class Program {
    7. [STAThread]
    8. static void Main()
    9. Test();
    10. Application.EnableVisualStyles();
    11. Application.SetCompatibleTextRenderingDefault(false);
    12. Application.Run(new frm_Template());
    13. Properties.Settings.Default.Save();
    14. }
    15. static void Test() {
    16. using (var entities = new myEntities()) {
    17. var Data10000 = entities.Tabelle1.ToList();
    18. }
    19. }
    20. }
    21. }

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

    Mein primäres Problem ist nicht die Performance. Ob nun das Laden der Daten oder die GUI lange braucht ist nicht wichtig.

    Da es lange dauert, will ich dem Nutzer entsprechende Hinweise geben, also
    • das Fenster sollte sich öffnen und was anzeigen
    • der Ladebalken sollte sichtbar sein
    • der WaitCursor sollte sichtbar sein.
    • Die Anwendung sollte sich nicht totstellen
    Das reine Laden von knapp 24.000 Datensätzen dauert rund 1,5sec, das Füllen des TreeView gute 27 sec und das Anzeigen nochmal etwa 2 sec.

    Verwendet habe ich folgendes Konstrukt nach deinem Vorschlag

    C-Quellcode

    1. static class Program {
    2. /// <summary>
    3. /// Der Haupteinstiegspunkt für die Anwendung.
    4. /// </summary>
    5. [STAThread]
    6. static void Main() {
    7. Test();
    8. Application.EnableVisualStyles();
    9. Application.SetCompatibleTextRenderingDefault(false);
    10. Application.Run(new MainForm());
    11. }
    12. static void Test() {
    13. long start;
    14. long ende;
    15. using (var context = new TreeViewContext()) {
    16. start = DateTime.Now.Ticks;
    17. var Daten = context.TreeViewsEntries.ToList();
    18. ende = DateTime.Now.Ticks;
    19. }
    20. Debug.Print(new TimeSpan(ende-start).TotalMilliseconds.ToString());
    21. }
    22. }

    MasterQ schrieb:

    Die Anwendung sollte sich nicht totstellen
    Na, leider muss sie sich ja doch ziemlich tot stellen.
    Weil es muss ja verhindert werden, dass der User irgendwas herum-klickst, was dem Lade-Vorgang in die Quere kommt.
    Ich hab für sowas ein IsBusy-Dialog gebastelt - ein Extra-Form, das anzeigt: Bitte warten.
    Async/Await: modaler IsBusy-Dialog, bis Nebenläufigkeit abgeschlossen



    Übrigens einen Treeview kann man auch mit Lazy-Loading befüllen.
    Also du baust einen Daten-Cache, und Child-Treenodes werden erst dann in einem Treenode erstellt, wenn letzterer sichtbar wird - etwa durch Expansion wiederum seines Parents.
    Das sollte so 28,5s bringen.

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

    Kasi schrieb:

    musst du wirlich 24.000 Datensätzte laden
    wie sind die Daten aufgeteilt im Treeview ? in Gruppen z.b. Bayern,Hessen.....


    Ich muss bei der Baumansicht alle Datensätze laden. Diese bestehen jedoch aus nur 4 Werten, Artikelnummer, Seriennummer, Auftragsnummer und Datum.

    Na, leider muss sie sich ja doch ziemlich tot stellen.
    Weil es muss ja verhindert werden, dass der User irgendwas herum-klickst, was dem Lade-Vorgang in die Quere kommt.
    Ich hab für sowas ein IsBusy-Dialog gebastelt - ein Extra-Form, das anzeigt: Bitte warten.
    Async/Await: modaler IsBusy-Dialog, bis Nebenläufigkeit abgeschlossen


    Na ja. Mit totstellen meinte ich, dass sie tot aussieht weil das Fenster nicht vollständig geladen ist und sich lange nix tut, etc. pp. Deswegen will ich ja den ProgressBar und den WaitCursor zeigen. Damit sollte klar sein, dass im Hintergrund gewerkelt wird.

    Dein IsBusy Dialog hilft mir nicht wirklich weiter. Ich kann mein Formular auch mit einem Button versehen, der dann nach User Aktion die Datensätze lädt. Doch das will ich nicht. Der Anwender öffnet bewusst das Fenster aus einem Menu heraus und am Ende soll alles angezeigt werden inkl. der Daten ohne dass weitere Aktionen des Nutzers notwendig sind.

    Und meine Frage lautet, wie ich das bewerkstellige. Das was du mit dem Button_Click anwirfst, soll bei mir automatisch geschehen. Nur weiß ich nicht wo ich im Programmablauf diesen Teil aufrufen soll.

    Das mit dem Lazy-Loading klingt gut. Ich möchte im Knotentext allerdings anzeigen, wie viele Kindsknoten vorhanden sind (auch im kollabierten Zustand). Da muss ich mir was überlegen. Aber es stimmt. Bei einem Aufruf des Formulars interessieren nur wenige Einträge und nicht immer alle.

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

    die Artikelnummern bilden die oberste Knotenebenen. Darunter liegen die SN und unter jeder SN die jeweils zugehörigen Auftragsnummern mit Datum

    Artikelnummern gibt es rund 60, SN rund 7000 (auf alle Artikelnummern ungleichmäßig verteilt) und Aufträge rund 24000 (auf alle Artikelnummern und SN ungleichmäßig verteilt).


    Ich lade jetzt alle Datensätze von der DB und halte sie im Speicher, füge aber nur die oberste Ebene in TreeView ein. Die Kindsknoten füge ich erst bei Bedarf ein.

    Das klappt gut und dauert nicht lange.

    Danke

    MQ

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

    Imo wäre da ein Parent-Child-View, 3-stufig, viel vorteilhafter als ein TV.
    Links DGV präsentiert die ANs, mitte DGV präsentiert die SNs der angewählten AN.
    Rechts DGV präsentiert die AN (diesmal bedeutet es: "AuftragsNummer") der angewählten SN.
    Gugge 'Parent-Child-View' auf die vier Views auf Video
    die Artikelnummern bilden die oberste Knotenebenen. Darunter liegen die SN und unter jeder SN die jeweils zugehörigen Auftragsnummern mit Datum

    Artikelnummern gibt es rund 60, SN rund 7000 (auf alle Artikelnummern ungleichmäßig verteilt) und Aufträge rund 24000 (auf alle Artikelnummern und SN ungleichmäßig verteilt).


    wenn du unbedingt eine TV nehmen willst...
    die Aufträge haben im TV nix zu suchen, Lade die Artikelnummer und SN, speicher die SN in Node.Tag
    lade dann diese Aufträge in Datagridview wenn eine SN im TV ausgewählt wurde

    oder mache es so wie EDR gesagt hat