Performance Problem mit DataSet / und Programmvorstellung "DasProgramm" - Achtung umfangreich

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

Es gibt 35 Antworten in diesem Thema. Der letzte Beitrag () ist von DerSmurf.

    Performance Problem mit DataSet / und Programmvorstellung "DasProgramm" - Achtung umfangreich

    Hallo ihr lieben
    Nach einer etwas längeren "kreativen Schaffenpause" - bedingt durch massive Unlust nach Datenverlust durch Hardwaredefekt (und schlampige Datensicherung) - bin ich nun wieder in der Vb.Net Welt angekommen.
    Derweil bin ich dabei mein Excel VBA Programm in eine Vb.Net Lösung umzuwandenln.
    Dies Programm kann letzlich alles, was ich für meine Tage im Einzaelhandel brauche.
    Bestellungen und Rechnungen erfassen, Artikel verwalten, Kundenbestellungen verwalten, Rechnungen automatisiert kontrollieren, Ean Code gestütze Bestellungen, uvm.
    Da es mir mein VBA Programm im Alltag sehr viel Arbeit abnimmt und Zeit einspart entstand der Name DasProgramm, denn für mich ist es DASProgramm.

    Eigentlich wollte ich meine vb.net Variante bis zum Ende programmieren, also mit allen Funktionen.
    Dabei habe ich den Anspruch, dass das Programm so gut ist, dass man es verkaufen könnte (auch wenn ich dies nicht vorhabe und das Prog nur für mich selbst nutzen werde).
    Jedoch brauche ich schon weit vorher eure Hilfe, denn die Performance meines DataSets ist "von Arsch".
    Außerdem macht es wahrscheinlich mehr Sinn, wenn mal jemand über das Programm schaut, bevor ich fertig bin - dann wirds von vornherein gescheit :)
    Denn ich würde mich immernoch als Vb.Net Anfänger mit recht soliden Grundkentnissen und recht guten Kentnissen mit DataSets beschreiben.

    Also mein Programm kann bisher folgendes:
    • verwalten von Kundenadressen und Emailversand direkt aus dem Programm
    • verwalten von Firmenbezogenen Bestellungen und Rechnungen
    • verwalten von Kundenbestellungen
    • verwalten von Artikelstammdaten (Preis, Artikelnummer, Lieferant, usw.)
    • Rechnungskontrolle (Umwandlung einer pdf Rechnung mittels FineReader in csv und Ablgeichen der Positionen mit Artikelstammdaten)
    • speichern von Zugangsdaten (passwörten)
    Bitte schaut hier mal rüber - Das Programm an sich sollte selbsterklärend sein, aber auch wenn es läuft wies soll, gibts dort bestimmt Code zu verbessern. Hier würde ich sehr gerne Tipps annehmen.

    Zu meinem akuten Problem:
    Ich habe das ArtikelDataSet per Code mit 10.000 Artikeln befüllt - dannach geht das Programm performancetechnisch in die Knie.
    Ein Klick auf "Artikel" - also zur TabPage zur Anzeige dieser Artikel - führt zu einer Verzögerung von gut einer Minute, bis die Seite geladen ist.
    Über die Volltextsuche per Suchen Button brauchen wir dann garnicht mehr reden.
    Hier hab ich ein bisschen Sorge, dass DataSet evtl. doch die falsche Wahl war - ich hoffe ,dass @ErfinderDesRades , oder jemand anderes mir das Gegenteil beweisen kann.

    Typische Datenmengen sind: Artikel DAtaSAet ca. 15.000 Einträge
    Bestellungen: ca. 1.000 pro Jahr
    Der Rest kann Mengenmäßig vernachlässigt werden

    Ich habe zwei DateSets angebunden, damit ich das unverschlüsselte ArtikeldataSet einfach durch Copy und Paste auf einen anderen PC kopieren kann, ohne Werte aus dem anderen DataSet zu ersetzen.
    Wenn ein DataSet deutlich zweckdienlicher ist, kann ich natürlich auch eine import- exportfunktion basteln.

    P.S.. Wenn es hilfreich ist, kann ich natürlich gerne auch mein VBA Programm anonymisieren (hier sind ja Daten und Code in der gleichen Datei).

    EDIT:
    Neue Version inklusive der Helpers hochgeladen - ist nun lauffähig.
    In den Einstellungen Button zum hinzufügen von 5.000 Artikeln in die Article DataTable eingebaut.
    Außerdem eine Articles.xml mit 15.000 Artikeln hochgeladen - diese muss in den Unterordner Data (wird beim ersten Programmstart automatisch erstellt)
    Dateien
    • DasProgramm.zip

      (761,24 kB, 119 mal heruntergeladen, zuletzt: )
    • Articles.xml

      (3,28 MB, 114 mal heruntergeladen, zuletzt: )

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

    @DerSmurf

    Bei so vielen Daten ist es nicht verwunderlich, dass es so lange braucht.

    DerSmurf schrieb:

    Ein Klick auf "Artikel" - also zur TabPage zur Anzeige dieser Artikel - führt zu einer Verzögerung von gut einer Minute, bis die Seite geladen ist.
    Über die Volltextsuche per Suchen Button brauchen wir dann garnicht mehr reden.

    Meinst du damit, die erweiterten Infos oder die Infos zu bearbeiten?

    Ich stelle es mir so vor: Du hast eine Liste von allen Daten und du klickst auf einen Eintrag und sagst "Weitere Informationen". Danach sollte es die Informationen ausgeben.

    Wenn das so ist, kannst du das Problem nicht sehr einfach lösen, weil das Programm jeden Eintrag in der DB(ich nehme an, dass du es mit einer SQL Datenbank machst) durchgeht, bis es einen passenden gefunden hat.

    Ich habe dein Projekt nicht durchgeschaut, weil man von der Beschreibung und meinen Annahmen auf die Lösung kommst, solange meine Annahmen richtig sind.
    @DerSmurf: Du hast die Helpers schon wieder nicht eingebunden :S
    @a.b_om: Lass bitte dieses Spekulatiusbacken. Ein tDS kann sehr effektiv und schnell sein, wenn man es richtig macht. Es geht hier darum den Flaschenhals zu finden, nicht ihn zu vermuten. Und: nein, das Ganze läuft ohne Datenbank.
    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.
    Hallo @a.b_om
    Sorry, ich war nicht schlau genug eine lauffähige Version meines Programmes auf meinen Arbeitsrechner zu bringen.
    Habe nur den Code und kein Visual Studio, daher kann ich dir nicht sagen, wie die TP genau heißt.
    Aber es gibt eine TabPage zur Anzeige der Artikel.
    Hier gibt es eine Textbox und ein gebundenes DGV.
    Das Anzeigen dieser Seite, also das umschalten von einer beliebigen TabPage auf eben diese Artikel TabPage dauert.

    a.b_om schrieb:

    Meinst du damit, die erweiterten Infos oder die Infos zu bearbeiten?

    ich meine damit einfach nur die Anzeige des gebundenen DGV

    a.b_om schrieb:

    Wenn das so ist, kannst du das Problem nicht sehr einfach lösen, weil das Programm jeden Eintrag in der DB(ich nehme an, dass du es mit einer SQL Datenbank machst) durchgeht, bis es einen passenden gefunden hat.

    Bei mir ist DataSet only angesagt.

    Edit:
    @VaporiZed
    Es freut mich sehr, dass du drüber guckst - oder drüber gucken würdest, wenn ich ein komplettes Programm hochladen würde :o)

    VaporiZed schrieb:

    @DerSmurf: Du hast die Helpers schon wieder nicht eingebunden

    Ich will dir ja auch zeigen, dass ichs wirklich bin :o)
    Ne, ich wollte eigentlich die Helpers Dateien im Debug Ordner lassen, aber irgendwie, naja, siehste ja...
    Ich mach heute Abend eine neues Zip (PC zuhause, geht leider nicht früher), mit Helpers und Programm.


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

    Ok, ich konnte das Programm jetzt zum Laufen kriegen. Was muss ich machen, um das Problem zu Gesicht zu bekommen? Datensätze hab ich ja anscheinend nicht.
    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.
    @DerSmurf
    Du kannst VisualStudio kostenlos herunterladen. Nur die Community Version. Das hilft vieles.

    Du meinst, du loopst jeden Eintrag durch und navigierst mit 2 Buttons? Ich empfehle dir einen TrueDBGrid (mit oder ohne Coponent One ist dir überlassen).
    Dan kannst du einen Eintrag auswählen (Doppelclick), eine neue Form öffnen nur mit diesem Datensatz. Dann kannst du auch einen Filter benutzen.

    Edit:
    Wenn die Seite nicht aktualiesiert obwohl man gedrückt hat.

    Ohne Datenbank, wie denn sonst?
    @DerSmurf: Umrahme das TabPage-Selecting folgendermaßen, dann geht's mit erstmal 10000 Artikel relativ fix (bei mir):

    VB.NET-Quellcode

    1. Private Sub TSArticles_Click(sender As Object, e As EventArgs) Handles TSArticles.Click
    2. ArticleDataGridView.DataSource = Nothing
    3. ArticleBindingSource.SuspendBinding()
    4. Me.TCMain.SelectedTab = TPArticles
    5. ArticleBindingSource.ResumeBinding()
    6. ArticleDataGridView.DataSource = ArticleBindingSource
    7. End Sub

    Bei diesem Problem hing ich auch mal fest.

    @a.b_om: Das wurde schon mehrfach gesagt bzw. angedeutet. Das Zauberwort heißt tDS-only alias DataSetOnly.
    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.
    Wie EdR immer zu sagen pflegt: Erstmal mit tDS anfangen und damit lernen, auf ne Datenbank kann man später immer noch wechseln oder die dranhängen. Es geht erstmal darum, mit Datenmodellen zu lernen bzw. diese zu beherrschen. Der nächste Vorteil ist auch, dass man eben keine Datenbank braucht, sondern alles später in ne Datei schreiben lässt, die man ggf. modifizieren und aber vor allem verschicken oder mitnehmen kann. Das wird bei vielen Datenbanken eher schwierig. Weitere Installationen braucht man nämlich bei tDS-only nicht. Die ganze Daten sind in Dateien und werden beim Programmlaufen in den RAM geladen.
    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
    Uff - das ist schon mein zweites Sorry. Ich habe versehentlich den Code zum erstellen der Daten gelöscht.
    Ich habe da beim @ErfinderDesRades - ich glaube in der Erklärung der vier Views - eine Methode gefunden in einer Schleife Daten ins DataSet zu schmeißen - so hab ichs gemacht.
    Also Variable mit neuer DataRow erzeugen und dann die Geschichte mit
    With Datarow
    .Name = "derName"
    .ArtNo = "dieArtikelNummer"
    End with
    usw.
    Das hab ich in eine Schleife gepackt, um entsprechend Daten zu erzeugen.
    Den Code werde ich heute Abend auch nachreichen - damit du nciht noch an meinem Programm rumschreiben muss.
    Wenn es nicht schon zu spät ist...

    VaporiZed schrieb:

    Umrahme das TabPage-Selecting folgendermaßen, dann geht's mit erstmal 10000 Artikel relativ fix (bei mir):

    Das macht mir Mut! Erstmal vielen Dank für diesen Ansatz.
    Ich kann mir aber gut vorstellen, dass hier schon die Ursache ist, also wie von dir beschrieben.
    Denn ich habe eine keine Mini Anwendung gebastelt um automatisch generierte csv Dateien aus dem DPD Versandprogramm DeliSprint einzulesen und im DataSet zu speichern.
    Hier kommt es auch zu einer unschönen Verzögerung, wenn das entsprechend gebindete DGV anzeigen lassen.
    Es sieht so aus als würde der PC "die Daten von oben nach unten in die Tabelle schreiben".
    Und das aktuell gerade mal 400 Einträgen-
    Da könnte deine Lösung ja auch helfen.

    Ich berichte heute Abend.
    Soho
    @VaporiZed mit deiner Codeänderung dauert bei mir das öffnen der TabPage mit 15.000 Artikeln 8 Sekunden.
    Mit meinem Urprünglichen Code dauert dies 37 Sekdunden.
    Beide Werte sind nur ca. habe ich im Kopf gezählt.

    Also auf jeden ein riesen, riesen Fortschritt und ich habe zum programmieren einen alten Laptop - groß aber langsam.
    Also sollten sich die 8 Sekunden auf meinem Arbeitslaptop noch reduzieren.

    Ich habe im Eingangsthread dann mal was lauffähiges hochgeladen. Also das Programm inkl Helpers.
    Außerdem noch eine Article.xml File mit 15.000 Einträgen. Diese muss in den Unterordner Data.
    Und in den Einstellungen einen Button zum hinzufügen von 5.000 Artikeln hingeschmissen (im Code der Mainform ganz unten).

    Nachdem das Hauptproblem nun gelöst ist - hat jemand Lust einen Blick auf den Code und dessen Struktur zu werfen, um mich ggf. auf Fehler, bzw. unsauberheiten hinzuweisen?

    Edit: und noch eine Frage.
    Ich speichere bei jedem beenden des Programmes einfach alles an Daten in die DataSets.
    Das dauert natürlich auch ein paar Sekunden - was ich aber nicht stört.
    Aber ist es nicht zweckdienlicher die Daten sofort nach Änderung in die xml zu schreiben?

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

    DerSmurf schrieb:

    hat jemand Lust einen Blick auf den Code und dessen Struktur zu werfen
    Kann ich machen. Dauert aber.

    DerSmurf schrieb:

    Aber ist es nicht zweckdienlicher die Daten sofort nach Änderung in die xml zu schreiben?
    Welchen Zweck verfolgst Du denn damit? Die dauernden Dateizugriffe bremsen extrem. Denn bedenke: Jedes Mal den kompletten tDS-Inhalt abzuspeichern, dauert bei mir ca. 4 Sekunden. Du kannst zwar auch einzelne Tabellen abspeichern. Aber kannst ja mal testen, ob das sooo performant ist. Alternativ - aber mit viel Vorsicht - könntest Du ggf. das Speichern auch nebenläufig (z.B. in nem anderen Thread oder Task oder wieauchimmer) machen. Da musst Du nur aufpassen. Nebenläufigkeit hat viele Tücken
    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.
    Ich habe natürlich überhaupt keine Eile.
    Bin froh, dass ich überhaupt in dieser Art Hilfe bekomme :thumbsup:

    VaporiZed schrieb:

    Welchen Zweck verfolgst Du denn damit?

    das weiß ich leider nicht.
    In meinem VBA Programm habe ich eine Funktion im "workbook.close Event", welches mir die Datei speichert.
    Trotzdem drücke ich ab und an auf Strg+S - weil ich mich dann irgendwie sicherer Fühle.
    Ist wohl eine Macke von mir.
    Ich werd mich wohl einfach dran gewöhnen, nix speichern zu müssen.
    Es könnte ja auch von Vorteil sein - wenn ich Mist baue, was lösche, was ich nicht hätte löschen sollen, kann ich mein Programm ja unsanft beenden und ein speichern unterdrücken. Das könnte ja auch ganz nett sein.

    Edit: ist denke ich selbstverständlich - aber nur zum sichergehen.
    Fragen zum Programm die nicht richtig mit diesem Thread zu tun haben, beantworte ich natürlich auch gerne per PN.
    Ja gut, einen Speichern-Button kannst Du Dir auch so einbauen. Und notfalls könntest Du Dir auch Dein Tastenkürzel einbauen.
    Zum Thema Artikelliste: Ich find es ein wenig Overkill, alle Artikel anzeigen zu lassen. Belass es doch bei einer leeren Liste, wo Du dann ein Suchfeld hast, wo Du dann Teilsuchbegriffe eingibst und Dir die passenden Ergebnisse auflisten lässt. Das geht ziemlich flink. Oder brauchst Du > 5000 Artikel in einer Liste, um gut arbeiten zu können?
    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.
    Evtl Offtopic:

    Um zu vermeiden dass ich wichtige Daten ausversehen lösche, lösche ich sie gar nicht erst, sondern setze in meinen Tabellen die Spalte "Gelöscht" auf True und zeige die entsprechenden Daten dann einfach nicht mehr an.

    Klar, dadurch hat man später viel Datenmüll und verschenkt Speicher, aber in meinem Arbeitsumfeld ist das wirkliche löschen von Daten teilweise rechtlich untersagt.

    VaporiZed schrieb:

    Ich find es ein wenig Overkill, alle Artikel anzeigen zu lassen.

    Manchmal kann es doch so einfach sein xD
    Ich habe einfach alle Artikel anzeigen lassen, weil das in meinem jetzigen WWS (Kaufversion von CTO EHO) eben auch so ist.
    Aber noch nie bin ich die Liste durchgegangen, sondern immer suche ich nach irgendwas.
    Also brauch ich da nicht alle Artikel drinne.
    Lange Ladezeiten entstehen üblicherweise, wenn im gebundenen Datagridview Spalten auf AutoSizeColumnMode.AllCells stehen.
    Dann ist das DGV irrsinnig beschäftigt, die richtige Spaltenbreite einzustellen - anscheinend macht es das für jeden Datensatz neu, und geht dabei alle Datensätze durch, und keine Ahnung, wie die das geschafft haben zu verbocken - es ist echt ein lausiger Buck, für dens imo keine technische Notwendigkeit gibt.
    Also das mal überprüfen, ob im DGV, was viele Zeilen anzeigt, wie da der AutoSizemode steht.
    AutoSizemode ist sowohl eine Einstellung der einzelnen DGV-Column als auch eine Einstellung des gesamten DGVs - da muss man beides nachgucken, um da sicher zu gehen.

    Dieses Problem hat nix mit DatasetOnly zu tun - würde das DGV aus einer DB befüllt, verhielte es sich ebenso.

    (also wenns das jetzt ist)
    Jupp Ist bei mir genauso. Dabei ist es egal ob ich meinen Code zum anzeigen der TabPage nutze.
    Also einfach nur das Anzeigen, oder den "erweiterten" Code von @VaporiZed, mit Bindingunterdrückung.
    In beiden Fällen - klick - und da!
    Vielen Dank @ErfinderDesRades

    Nun tritt aber ein neues Problem auf den Plan.
    Wenn ich nicht mit Autosize arbeiten kann - was auch Codetechnisch zu Verzögerung führt, habe ich versucht,
    dann muss ich ja die Breiten der Spalten im DGV speichern, damit ich nicht bei jeder Programmausführung die Spalten neu hin und herziehen muss.
    Wie mache ich dies am einfachsten?
    Nee, einfach nach dem Anzeigen der Daten bzw. nach dem ResumeBinding die AutoSizeModes der Columns selber auf die gewünschten Werte setzen. Nur eben nicht beim Datenladen aktiv drinne haben.

    ##########

    Öhm ... ich korrigiere. Fill ist zeitlich ziemlich billig. AllCells hingegen nicht.
    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.

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