Dataset only -> DB / Welches System und wie?

  • VB.NET
  • .NET (FX) 4.0

Es gibt 96 Antworten in diesem Thema. Der letzte Beitrag () ist von Bit-Bieger.

    Nochmal:

    Ich habe eine funktionierende Anwendung mit DataSet und Access-Datenbank-Datei. Das möchte ich gerne genau so beibehalten (bis ggf. irgendwann ein SQL-Server was anderes verlangt) -
    nur eben die Ladezeiten deutlich verkürzen.

    Was ich nicht möchte ist jetzt die komlette Anwendung umzuschreiben- denn eigentlich läuft alles und ich denke man bekommt das hin.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    tragl schrieb:

    Gibt es eine saubere Möglichkeit beim Öffnen eines Programm-Moduls nur die geforderten Daten zu laden (das geht ja in jedem Fall) und trotzdem
    das DataSet weiter zu nutzen? Also quasi statt einem BindingSource-Filter einen "LadeDatenAusDatenbank"-Filter nutzen.
    Ja, dazu ist eine Datenbank ja da.
    In der DBPersistance gibts die Methode CustomFill(), da gibste die zu befüllende DataTable an und eine Where-Clausel, damit nicht die komplette DB-Tabelle geladen wird.
    Man muss dabei aber umsichtig zu Werke gehen, weil man keine Datensätze anfordern kann, deren Parent-Datensätze noch nicht im Dataset sind.

    Sehr wichtig ist auch, genau zu untersuchen, was eigentlich lange dauert. Sehr oft ist so eine Befüllung nämlich schnell, und was langsam ist, ist das angebundene DatagridView.
    Oder du hast wirklich einen phänomenal schnell wachsenden Datenbestand.
    Ich hab datasetOnly mit Datasets gearbeitet, die haben sich in 3s aus einer 400MB-DatenDatei befüllt.
    Vielleicht ist auh Access total langsam. Ich hatte auch mal über Jahre eine iwie verdrehte SqlServer-installation, die hat 5s für 50 Datensätze gebraucht - also war unbrauchbar.

    ErfinderDesRades schrieb:

    Man muss dabei aber umsichtig zu Werke gehen, weil man keine Datensätze anfordern kann, deren Parent-Datensätze noch nicht im Dataset sind.

    ich geh mal davon aus, dass ne Fehlermeldung kommt wenn ich was falsches befüllen will?

    ErfinderDesRades schrieb:

    Oder du hast wirklich einen phänomenal schnell wachsenden Datenbestand.

    jain - sind schon einige Daten

    Ich muss mal ne stopwatch setzen, dann weiß ich ja was lange dauert. Wird aber das Befüllen des DataSets sein. Auf meinem PC geht das flott (Datenbank-Datei und Programm sind auf der SSD) - Netzlaufwerk, naja der Laufwerksserver liegt irgendwo
    im CompanyNet. Mal gehts schneller, mal langsam, mal echt so richtig langsam.

    @ErfinderDesRades:

    Hier mal die Zeitauswertung für's ReloadDTS

    VB.NET-Quellcode

    1. Dim sw As New Stopwatch
    2. sw.Start()
    3. Dts.ReloadDts()
    4. msgInformation(sw.Elapsed.ToString)


    Auf meinem Rechner im Debug-Mode:


    Von meinem Rechner aus in's CompanyNet (schnelle Leitung):


    4-7 Sekunden ist OK - man bedenke aber dass das bei jedem Programmmodul gemacht wird.
    ich reiche morgen den Screen von der Firma nach - das dauert da wesentlich länger.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    Das schwierige an der Zeitmessung ist, dass da evtl. BindingSources dranhängen, die während des Ladens iwelche Datagridviews befüllen.
    Du musst sicherstellen, dass während dts.ReloadDts() keine BindingSource am Dataset angeschlossen ist - sonst misst du die Befüllung von Dts+DGV - nicht die Befüllung des Dts. Und das ist u.U. stark verfälscht, weil das DGV zig-fach langsamer sein kann.



    tragl schrieb:

    man bedenke aber dass das bei jedem Programmmodul gemacht wird.
    Was ist bei dir ein "Programm-Modul"?
    Du lädtst doch hofflich nicht mehrmals dieselben Daten, oder sowas ?

    ErfinderDesRades schrieb:

    Du lädtst doch hofflich nicht mehrmals dieselben Daten, oder sowas ?

    nein.

    Als Programm-Modul sehe ich jede "Aktion" die über den TreeView gestartet wird an. Der Urlaubsplaner ist z.B. ein Programm-Modul, die Arbeitszeiten sind ein Programm-Modul etc.
    Hier noch die Zeit zum Laden von der Firma aus:


    Ich muss die Daten aber auch jedesmal frisch laden, da diese sich ja durch einen anderen User evtl. geändert haben können. Ich bin mir sicher, wenn ich hier nur die Daten lade die wirklich gebraucht werden, sich die Zeit
    enorm verkürzen wird. Die Bindingsources abstöpseln würde ja keinen Sinn machen, denn die brauche ich ja tatsächlich... aber wie man an den Zeitunterschieden erkennen kann muss es am Netzlaufwerk und somit dem reinen Laden
    der Daten zusammenhängen. Der Rest müsste ja am PC selbst erfolgen (DGV's befüllen etc.) und die sind alle "schnell genug" - das weiß ich weil es mit DataSet only bei weitem nicht so lange gedauert hat.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    25s!!!
    Das darf nicht wahr sein - eure DB-Installation ist wohl vermurkst.
    Ah - man sollte auch noch messen, wie lange eine Connection zu öffnen braucht.
    Vielleicht kann man anne DB auch Connection-Pooling einstellen - dasses an sowas liegt.

    Würde ich auch vorziehen, ehe man sich an inkrementelle Befüllung macht. Weil an einer vermurksten DB hat man so oder so keine Freude.

    Übrigens mehrmals messen, bei mir pendelt ConnectionOpen sich erst beim dritten Mal auf 3-4ms ein.

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

    ErfinderDesRades schrieb:

    eure DB-Installation ist wohl vermurkst


    was heißt DB-Installation? Ist doch nur eine .mdb-Datei auf einem Netzlaufwerk. Und der Zugriff darauf geht mal schneller und mal langsamer (je nach Leitung).
    An meinem Arbeitsplatz haben wir z.B. nur 4Mbit/s CompanyNet-Anbindung. Daheim hab ich 100Mbit/s - dann kommt's drauf an, wieviel downstream das CompanyNet macht wenn ich
    mich mit VPN einwähle. Deshalb kommen bei mir 4-7 Sekunden raus, in der Firma dann 25...

    Für ReloadDTS wird aufgerufen
    _Persistance.FillAll()
    und die macht folgendes (hast du ja selbst gecodet :P )

    VB.NET-Quellcode

    1. Public Sub FillAll()
    2. _Dts.Clear()
    3. Using Connection_EnterOpen()
    4. Dim enforced = _Dts.EnforceConstraints
    5. _RankedTables.ForEach(Sub(tb) tb.BeginLoadData())
    6. _RankedTables.ForEach(Sub(tb) GetAdapter(tb).Fill(tb))
    7. _RankedTables.ForEach(Sub(tb) tb.EndLoadData())
    8. _Dts.EnforceConstraints = enforced
    9. End Using
    10. End Sub



    also nix anderes als das Dataset zu leeren und wieder frisch aus der DB-Datei zu befüllen. Wenn du eine andere / sinnvollere Idee hast, anstatt inkrementell zu befüllen - dann her damit.
    Meiner Meinung nach der einzig sinnvolle Weg aktuell.

    Ich könnte auch komplett auf DataSet verzichten und mit SQL arbeiten aber das fänd ich sehr unschön - zumal dann zur Laufzeit ja dann doch wieder etliche DataTables im Speicher rumfliegen und zwar temporär,
    dann kann ich auch gleich die "fest verbauten" im DataSet nutzen, aber eben nicht alle oder nicht mit allen Daten befüllen

    EDIT: @ErfinderDesRades: hast du ein funktionierendes Beispiel für CustomFill?
    Dts._Persistance.CustomFill(Dts.Datenabfrage, "*", "WHERE expGesellschaft = ?", _uGesellschaft)
    Damit soll er mir alle Daten holen, die meiner Gesellschaft zugehörig sind. Der Commandtext macht auch irgendwie keinen Sinn
    er müsste eigentlich lauten SELECT * FROM `Datenabfrage` WHERE `expGesellschaft` = _uGesellschaft oder so. preamble weglassen geht nicht.

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    Zunächstmal wie gesagt: Miss mal die zeiten bei mehrmaligem Öffnen der Connection.

    Dann hatte ich gedacht DatasetOnly auf dem Netzlaufwerk sei flott gegangen. Also die Datenübertragung sei nicht so daneben gewesen.
    Aber scheints hatte ich da falsch gedacht, und entweder war DatasetOnly nie auffm Netzlaufwerk oder beim DB-Zugriff werden die Daten dann iwie anners transportiert.

    CustomFill-Samples sind im DBPersistance-Tut doch drin?
    Jo, du verwendest nicht richtig. Das * ist überflüssig, weil bei einem dataset kann man immer nur alle Spalten der Tabelle selectieren - das extra anzugeben kann man sich sparen.
    Probierma Dts._Persistance.CustomFill(Dts.Datenabfrage, "WHERE expGesellschaft = ?", _uGesellschaft)
    Das addressiert die .CustomFill()-Überladung ohne Preambel.

    Indem du da zwei Strings angibst stellt dein "*" den preamble-Parameter dar.
    Aber als Preambel vorgesehen sind nur Schlüsselworte wie Top 100 oder Distinct - hab ich das nicht dran-kommentiert? (bei mir zuhause hab ich das ;) )

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

    ErfinderDesRades schrieb:

    entweder war DatasetOnly nie auffm Netzlaufwerk


    richtig, denn DataSet Only ist ja nicht Multi-User-fähig.

    ErfinderDesRades schrieb:

    Probierma

    da kommt auch kauderwelsch bei raus leider...



    ErfinderDesRades schrieb:

    Miss mal die zeiten bei mehrmaligem Öffnen der Connection.


    kann ich gerne tun aber ändert nix dran, dass es zu langsam ist. vielleciht sind's dann ma 18 oder 21 statt 25 sekunden.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    ErfinderDesRades schrieb:

    ah - vmtl ist _uGesellschaft ein String

    jo ist ein String - soll aber auch mit allen Datentypen klappen.
    Könnte man das so Coden, dass man damit umgehen kann wie mit deiner FilterX-Extension?
    Und ich fände es sinnvoll, sqlAfterFrom optional zu machen - dann hat man die Möglichkeit die komplette Table (aber nicht das komplette DataSet) neu zu befüllen. (Finde ich mit "" recht unschön)

    Hab grad ma einen Test und Messungen gemacht:

    Für "Mitarbeiter" muss ich zusätzlich die Tabellen "Benutzer" und "UCP" neu befüllen
    ClearRecursive: 00:00:00.0091594
    Rest: 00:00:00.1573454 'Mitarbeiter

    ClearRecursive: 00:00:00.0000023
    Rest: 00:00:00.0361020 'Benutzer

    ClearRecursive: 00:00:00.0000024
    Rest: 00:00:00.1221573 'UCP

    Für Datenabfrage reicht tatsächlich die Tabelle "Datenabfrage" selbst

    ClearRecursive: 00:00:00.0088950
    Rest: 00:00:03.4672054

    Ist eine Sekunde weniger als das komplette DataSet zu befüllen. Wobei "Datenabfrage" mit die größte Tabelle in meiner Datenbank ist.
    Also sooo viele Einsparungen wird's wohl nicht geben - aber vielleicht reicht das ja schon. Vielleicht wird's aber besser wenn nur die benötigten Daten geladen werden anstatt
    komplette Tabellen. Ich teste das am Montag oder Dienstag mal von der Firma aus. Wenn's nur noch 10 statt
    25 Sekunden sind, dann wäre das schonmal besser ;)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    grad fällt mir eine Lösung auf die Schnelle ein (mann ich bin ein Depp!). Probierma:

    VB.NET-Quellcode

    1. Dts._Persistance.CustomFill(Dts.Datenabfrage, "", "WHERE expGesellschaft = ?", _uGesellschaft)
    Damit gibst du expliziet preamble = "", sqlAfterFrom = "WHERE expGesellschaft = ?" an, und _uGesellschaft kann dann nur noch in args landen.

    ErfinderDesRades schrieb:

    Probierma:


    Damit kommt folgender CommandText: "Select `Datenabfrage`.* from `Datenabfrage` WHERE expGesellschaft = @p0 "
    und Debug meckert: Für mindestens einen erforderlichen Parameter wurde kein Wert angegeben.

    Ich kann aber erst morgen weiter gucken - heute kein Zeit mehr.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    ErfinderDesRades schrieb:

    Uih - da hab ich mal einen mördermässigen Sql-Generator gebastelt, der konnte glaub sowas: "Lade diese Datensätze, und alle untergeordneten".


    Oha, genau so etwas suche ich gerade. Wenn man das manuell macht, proggt man sich ja einen Wolf mit dem ganzen SQL-String-Gewurstel (im meinem Fall ca. 19 Tabellen) ;)
    Ganz zu schweigen von Anpassungen die durch nachträgliche Änderungen am Daten-Modell erfolgen...
    Benefit: Schnellere Ladezeiten, weniger Arbeitsspeicher (v.a. bei großen Datenmengen) und der Client bekommt nur die Daten für die er auch ne Berechtigung hat in den Ram geladen.