SQL Abfrage mit Async

  • VB.NET

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

    SQL Abfrage mit Async

    Hallo zusammen,

    ich möchte mich bezüglich dem Einsatz von Async/Await etwas informieren. Selbst habe ich bis jetzt mit dieser Technologie noch nicht gearbeitet (außer mit BackgroundWorker).

    Es geht um eine Applikation mit einer MySQL Verbindung. Die Applikation greift sowohl lokal als auch extern auf einen MySQL Server zu. Der Zugriff auf den externen MySQL erfolgt nicht über ein Webservice sondern über eine verschlüsselte Verbindung. Bei dem externen Zugriff kann es schon vorkommen, dass ca. 10000 Daten in ein DataGrid geladen werden müssen. Warum alle auf einmal, sei einmal nicht zu diskutieren. Logischerweise kommt es beim externen Zugriff zu Wartezeiten und die Oberfläche wartet/friert ein bis die Daten da sind. Ich würde gerne die Datenbank Anfrage async machen und nach dem Erhalt der Daten das DataGrid befüllen.

    Meine Fragen dazu:

    1) Macht das Sinn?
    2) Hat jemand so etwas schon gemacht? Ich kenne nur HTTP Requests diesbezüglich, aber kein direktes Absetzen eines SQL Befehles
    3) Würde ein BackgroundWorker auch reichen oder ist Async/Await einfach die bessere Technologie?

    Habe mir das Tut vom @ErfinderDesRades angesehen, aber da muss ich mich noch wirklich einlesen.

    Danke für euere konstruktiven Hinweise...
    zwischenzeitlich habich einfacheres Tutorial verzapft: codeproject.com/Articles/10296…ithout-any-additional-Lin

    Jo - Backgroundworker ist stinkender Müll - wars schon immer.

    Übrigens tritt eiglich bei jedem fast immer dasselbe Missverständnis auf: Nämlich dass das Daten holen lange dauert.
    In den allermeisten Fällen, ists aber die Befüllung des DGVs.
    Und da das DGV ein Control ist, kann man da mit Threading nichts machen.

    Also teste erstmal: Füll deine Daten in eine DataTable - nicht in ein DGV.
    Und miss die Zeit.

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

    @ErfinderDesRades
    ja, dieses Beispiel habe ich schon gefunden und werde es mir einmal genauer ansehen.

    Bevor ich mich jetzt einmal in Async/Await vertiefe, eine Frage: Wenn ihr so etwas macht, wie zeigt ihr dem Benuzter dass im Hintergrund gearbeitet wird? Einfach ein PopUp Fenster mit "Bitte warten..." und nach dem Erhalt schließen oder gibt es dazu auch ein Technologie? Weil mit Async kann ich ja nicht auf ein Control in der Form oder ähnliches zugreifen.

    EDIT:

    ...ach da ist mir noch etwas einfgefallen:

    Beim Einsatz von Async/Await wird ja die Form soweit aufgebaut und in Hintergrund (Thread) etwas gemacht. D.h. Man muss dafür sorgen, dass der Benutzer die Form nicht verlässt bevor die Daten vom Thread da sind oder ?

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

    Das tolle ist, dass man oft den Dialog absichern muss solange Daten async geladen werden. Weil die User wild klickern… am Ende hat man oft keinen Vorteil das ganze async zu Laden, weil der User eh nichts tun kann ohne die Daten…
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

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

    @ErfinderDesRades

    Das mit den Daten befüllen in eine DataTable und die Zeit messen habe ich ja schon gemacht. Es ist sehr unterschiedlich, je nach Internetverbindung, bis die Daten in der DataTable sind. Die Werte liegen von 3 - 8 Sekunden je nach zu ladenden Datensätzen. Deshalb kam mir die Idee mit Async/Await und auch meine weiteren Fragen, wenn Async/Await zum Einsatz kommt.

    Das Anzeigen in einem DataGrid bei einer großen Datenmenge ist eine andere Geschichte.

    @mrMo

    ja, da hast du Recht, aber es ist schon einmal gut, wenn die Form komplett da ist. In der schnelllebigen Zeit, will keiner mehr warten auch wenn es nur eine Sekunde oft dauert. Dann heißt es oft, dass das Programm langsam ist.

    In unserer Applikation kann der Benutzer von einer Form in eine andere wechseln. Es wird die Single Document Interface Technologie eingesetzt. D.h. bei Async/Await muss auf jeden Fall verhindert werden, dass der Benutzer nicht in eine andere Form wechselt, solange die Daten nicht da sind. Naja, das wird sicher etwas trickreich ;)

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

    Jo, dann zu deinen anderen Fragen in post#3:
    Das meiste steht alles im gegebenen Tut.
    Nebenläufigkeit ist immer ein Paket von Massnahmen - eins führt zum anderen bis hin zum (dort) genannten Bündel:
    We saw several demands immediately come up, so one can see the purpose "responsive gui" as a conglomerate of five challenges: 1) Responsivity, 2) Restrict Gui and release it afterwards, 3) Progress-Report, 4) Cancelation, 5) Exception-Handling.

    Zu 2 - Restrict Gui - habich inzwischen einen IsBusy-Dialog veröfflicht, der verhindert, dass der User Unfug klickst, aber dennoch Cancellation ermöglicht: Async/Await: modaler IsBusy-Dialog, bis Nebenläufigkeit abgeschlossen
    OK, dann danke ich euch einmal für euer Hilfe.

    Edit:

    @ErfinderDesRades

    ich habe jetzt einmal versucht zu deinem Tut (Async/Await: modaler IsBusy-Dialog, bis Nebenläufigkeit abgeschlossen) den ProgressBar zu updaten.
    Habe zwar mit Tasks (Async/Await) noch nicht wirklich gearbeitet. Wahrscheinlich sind meine Erweiterungen/Änderungen falsch bzw. nicht richtig codiert, aber es funktioniert soweit.

    *EXE-Anhang entfernt*

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Marcus Gräfe“ ()

    @ErfinderDesRades, @mrMo

    Bezugnehmend nochmal auf die asynchrone Datenbankabfrage, würde ich gerne zwei unabhängige Abfragen gleichzeitig starten. Das sollte ja möglich sein. Derzeit laufen die beiden Abfragen nacheinander, was eigentlich nicht sein muss.

    Ich habe mir dazu eine SQL-Klasse für die Datenbank abfragen geschrieben. Die wichtigsten Prozeduren sind diese beiden:

    VB.NET-Quellcode

    1. Public Async Function SelectDataAsync(ByVal pSQL As String) As Task(Of DataTable)
    2. Try
    3. Dim DBTable As DataTable = await Task.Run(Function() ReadData(pSQL))
    4. Return DBTable
    5. Catch ex As Exception
    6. _error = "MySQLFunctions -> SelectDataAsync: " + ex.Message
    7. Console.WriteLine(_error)
    8. Return Nothing
    9. End Try
    10. End Function
    11. Private Function ReadData(pSQL As String) As DataTable
    12. Try
    13. _error = ""
    14. If conn Is Nothing Then
    15. conn = New MySqlConnection(ConnString)
    16. End If
    17. Console.WriteLine(pSQL)
    18. conn.Open()
    19. Using cmd As MySqlCommand = New MySqlCommand(pSQL, conn)
    20. cmd.CommandTimeout = 300
    21. ' GW: 1.2.2021
    22. Using dataReader As MySqlDataReader = cmd.ExecuteReader()
    23. DBTable = New DataTable
    24. DBTable.GetData(dataReader, True)
    25. End Using
    26. End Using
    27. conn.Close()
    28. Return DBTable
    29. Catch ex As Exception
    30. conn.Close()
    31. _error = "MySQLFunctions -> SelectDataAsync: " + ex.Message
    32. Console.WriteLine(_error)
    33. Return Nothing
    34. End Try
    35. End Function


    In meinem Programm verwende ich dann folgende Prozedur um die Daten zu laden.

    VB.NET-Quellcode

    1. Private Sub LadeDaten(_DB As String, _Table As String)
    2. Dim TaskListe As List(Of Task(Of DataTable)) = New List(Of Task(Of DataTable))
    3. Try
    4. dataTableSpWan = New DataTable
    5. dbSQL = "SELECT * FROM " + _DB + "." + _Table
    6. TaskListe.Add(Task.Run(Function() SelectDataAsync(dbSQL)))
    7. dataTableCommentWan = New DataTable
    8. dbSQL = "SHOW FULL COLUMNS FROM `" & _Table & "` ;"
    9. TaskListe.Add(Task.Run(Function() SelectDataAsync(dbSQL)))
    10. ' Beide Abfragen gleichzeitig starten
    11. Await Task.WhenAll(TaskListe.ToArray())
    12. ' Ergebnisse lesen
    13. dataTableSpWan = CType(TaskListe(0).Result, DataTable)
    14. dataTableCommentWan = CType(TaskListe(1).Result, DataTable)
    15. ' weiterer Code wäre nur zur Anzeige der Daten
    16. Catch ex As Exception
    17. End Try
    18. End Sub


    Beim ersten Aufruf der Prozedur "LadeDaten" passt noch alles. beim zweiten Mal werden die Tasks nicht zu Ende ausgeführt oder es kommt "Nothing" zurück, obwohl Daten vorhanden sind.

    Die Variante mit der TaskListe als List(Of Task(Of DataTable)) habe ich in einem Tutorial gesehen. Allerdings wurden dort nur Berechungen durchgeführt und keine Datenbankabfragen.

    Hat jemand eine Idee was da nicht passt? Ich bin bezüglich der Async Programmierung ein Neuling und komme beim Absetzen von mehreren Tasks nicht wirklich weiter.
    nach meim Verständnis ist Async "nur" dafür gut, Nebenläufigkeit zum Gui-Thread herzustellen.
    Wenn du da noch mit mehrere Task paralell herum-optimieren willst, dann ist wohl Paralell.For() das geeignete Werkzeug.
    und vlt. iwas mit Task.WaitForAll() oder sowas.

    Da musste dich dann wieder meinem vbParadise-Tut zum Thema Async zuwenden - da habich so allerlei Möglichkeiten ausgelötet.
    Tatsächlich gebraucht habichs denn aber noch nie.

    (Also ich glaub nicht, dass du damit viel Zeitgewinn rausholen wirst)

    GerhardW schrieb:

    Hat jemand eine Idee was da nicht passt?
    Vor allem der TryCatch passt nicht - mach den weg, dann bekommst du überhaupt Anhaltspunkte dafür, was falsch läuft.

    Überhaupt empfehle ich dir dringend, alle deine TryCatchens wegzumachen. TryCatch ist ein heißes Eisen