SQL-Express langsam / Konzept falsch?

  • VB.NET
  • .NET (FX) 4.0

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von SchorschCode.

    SQL-Express langsam / Konzept falsch?

    Hallo zusammen,

    ich würde gerne wissen, ob mein Konzept falsch ist oder was ich verändern muss, damit die Verarbeitung schneller läuft.

    Die Tabelle tblAuftragKopf mit ca. 300.000 Datensätzen wird gelesen. Aus der Tabelle tblAuftragKopfdaten mit insgesamt ca. 1.000.000 Datensätzen werden die Datensätze gefiltert, welche dieselbe Auftragsnummer haben. In der Tabelle tblAuftragPositionen stehen verschiedene Werte, die für eine Berechnung herangezogen werden. Der Kopfsatz wird verändert, abschließend wird die komplette Tabelle gespeichert. Das funktioniert auch soweit, allerdings ist die Verarbeitung sehr langsam.

    Dies ist nur ein Beispiel. Leider ist es in der Realität nicht möglich, die beiden Tabellen zu verknüpfen, da die "Auftragsnummer" für das Filtern der Positionssätze zunächst aufbereitet werden muss; sie steht nur in einem anderen Format zur Verfügung. In der Realität geht es nicht um Aufträge, ich wollte nur das Problem schildern.

    Hier der Code:

    VB.NET-Quellcode

    1. Public strPcCONN As String
    2. Public sqlCONN As SqlConnection
    3. Public daKOPF As New SqlDataAdapter
    4. Public dsKOPF As New DataSet
    5. Public dtKOPF As New DataTable
    6. Public drKOPF As DataRow
    7. Public daPOS As New SqlDataAdapter
    8. Public dsPOS As New DataSet
    9. Public dtPOS As New DataTable
    10. Public drPOS As DataRow
    11. Dim strFILTER As String
    12. Dim dblWERT As Double
    13. ...
    14. strPcCONN = "Server=.\SQLExpress;AttachDbFilename=C:\TEST\TESTDB.mdf;Database=TESTDB;Trusted_Connection=Yes;"
    15. sqlCONN = New SqlConnection(strPcCONN)
    16. sqlCONN.Open()
    17. ...
    18. strPcSQL = "SELECT * FROM tblAuftragKopf"
    19. daKOPF = New SqlClient.SqlDataAdapter(strPcSQL, sqlCONN)
    20. daKOPF.Fill(.dsKOPF, strPcSQL)
    21. dtKOPF = dsKOPF.Tables(strPcSQL)
    22. dtKOPF.PrimaryKey = New DataColumn() { dtKOPF.Columns("AKID")}
    23. daPOS = New SqlClient.SqlDataAdapter("SELECT * FROM tblAuftragPositionen", sqlCONN)
    24. daPOS.Fill(dsPOS, "tblAuftragPositionen")
    25. dtPOS = dsPOS.Tables("tblAuftragPositionen")
    26. dtPOS.PrimaryKey = New DataColumn() { dtPOS.Columns("APID")}
    27. For Each drKOPF In dtKOPF.Rows
    28. strFILTER = "(APAUFTRAG = " & drKOPF!AKAUFTRAG & ")"
    29. Dim drROWS() As DataRow = dtPOS.Select(strFILTER)
    30. If drROWS.Length > 0 Then
    31. ... irgendwelche Berechnungen; Ergebnis steht in dblWERT
    32. End If
    33. drKOPF!AKERGEBNIS = dblWERT
    34. Next
    35. cmb = New SqlCommandBuilder(daKOPF)
    36. daKOPF.Update(dtKOPF)


    Was ist falsch an meinem Konzept? Wie kann ich die Verarbeitung beschleunigen?


    Bin für jeden Hinweis dankbar!
    Hallo

    SchorschCode schrieb:

    Was ist falsch an meinem Konzept?

    Ich würde sagen das hier: SELECT * FROM tblAuftragPositionen, SELECT * FROM tblAuftragKopf

    Es ist nie eine gute Idee ALLE Datensätze abzurufen. Das kann nur langsam sein/werden.

    SchorschCode schrieb:

    Die Tabelle tblAuftragKopf mit ca. 300.000 Datensätzen wird gelesen. Aus der Tabelle tblAuftragKopfdaten mit insgesamt ca. 1.000.000 Datensätzen werden die Datensätze gefiltert, welche dieselbe Auftragsnummer haben.

    Bei so vielen Datensätzen muss unbedingt ein Filter rein (WHERE) um nur die Datensätze zu bekommen welche auch benötigt werden.

    SchorschCode schrieb:

    Leider ist es in der Realität nicht möglich, die beiden Tabellen zu verknüpfen, da die "Auftragsnummer" für das Filtern der Positionssätze zunächst aufbereitet werden muss

    Du könntest uns ja mal zeigen in welchem Format die Daten vorliegen (an beiden Seiten), dann könnte man ja sehen ob man SQL die Arbeit überlassen kann. Dann würdest du nur die Datensätze bekommen welche auch wirklich benötigt werden.


    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    danke für Deine Antwort.

    Es ist leider so, dass ich eben alle Datensätze bearbeiten muss. Aber es ist auch so, dass das Laden dieser vielen Datensätze in den DataAdapter viel Zeit benötigt.

    Aber Du hast mich auf eine Idee gebracht: Ich müsste in der tblAuftragKopf ein Kennzeichen hinterlegen, ob der Datensatz schon verarbeitet wurde. So könnte ich immer nur diejenigen öffnen, die noch nicht verarbeitet wurden. Das wäre eine Lösung.

    Gibt es eine Möglichkeit, den DataAdapter und somit das Laden in den Speicher zu umgehen?

    Vielen Dank und Gruß nach Wiener Neustadt

    Schorsch

    SchorschCode schrieb:

    Gibt es eine Möglichkeit, den DataAdapter und somit das Laden in den Speicher zu umgehen?

    Das musst du genauer definieren...

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Diese Zeilen hier dauern in der Ausführung sehr lange:

    VB.NET-Quellcode

    1. daKOPF.Fill(.dsKOPF, strPcSQL)
    2. '
    3. daPOS.Fill(dsPOS, "tblAuftragPositionen")


    Ich gehe davon aus, dass diese Befehle die Daten in den Speicher laden. Aber das müsste doch gar nicht sein; war ja unter VB6 auch nicht erforderlich. Bei kleinen Datenmenge ist es ja kein Problem, bei großen schon.

    Gruß
    Schorsch
    OK, das meinst du.

    Du kannst die Daten natürlich auch so abgrasen. Fast immer ist es aber so das man mit dem richtigen konzept die Daten erst gar nicht von der Datenbank übertragen muss.
    Aber das können wir nicht beurteilen. Empfehlen würde ich es.

    Aber auf die Frage:

    Nofear23m schrieb:

    Du könntest uns ja mal zeigen in welchem Format die Daten vorliegen (an beiden Seiten), dann könnte man ja sehen ob man SQL die Arbeit überlassen kann. Dann würdest du nur die Datensätze bekommen welche auch wirklich benötigt werden.

    Hast du keine antwort gegeben. Hier würde ich persönlich aber mal ansetzen.


    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Ah, sorry, vergessen. In der tblAuftragKopf steht z.B. als eindeutige Nummer 12300055555 . In der tblAuftragPositionen steht die Nummer im Format DE 55555. Es gibt auch eine Ländertabelle, mit der ich DE in 123 konvertieren könnte, aber das Problem sind die Leerstellen. Je nach Länge der Zahl 55555 müssen die Leerstellen mit Nullen aufgefüllt werden, so dass immer eine Zahl mit 8 Stellen (inkl. Ländercode sind es also 11) herauskommen muss.

    Diese Vorgehensweise hat natürlich mit Aufträgen nichts zu tun; es ging mir nur darum, das Problem zu verdeutlichen.


    Du kannst die Daten natürlich auch so abgrasen.


    Könntest Du mir bitte einen Tipp für einen Ansatz geben, wie ich das machen muss?

    Grüße

    Schorsch
    Nur so am Rande. Ich denke das man die Arbeit schon den SQL Server machen lassen könnte. Dann müsstest du ja nur die Daten abrufen welche du benötigst.
    Ausserdem kann man (den genauen Namen weis ich jetzt nicht mehr) eine art Virtuelle Spalten abrufen. Sprich. Per SQL wird beim Abrufen eine neue Spalte erstellt (virtuell) die die "Umgewandelten" Werte enthält. So hättest du schon mal alles im richtigen Format direkt nach dem anrufen und musst das alles nicht in einer Schleife machen.

    SchorschCode schrieb:

    Könntest Du mir bitte einen Tipp für einen Ansatz geben, wie ich das machen muss?

    Du könntest das über das DataTable machen.
    Schau mal hier: stackoverflow.com/questions/17…erate-through-a-datatable

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##