Code zur Anzeige von Daten aus DataSet optimieren (Ausführung dauert zu lange)

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

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

    Code zur Anzeige von Daten aus DataSet optimieren (Ausführung dauert zu lange)

    Guten Morgen
    Ich habe ein DataSet mit nicht ganz trivialer Struktur, zum Eintragen von Tageseinnahmen für verschiedene (zur Programmierzeit unbekannt vielen) Warengruppen.
    Dazu habe ich eine kleine Form, auf der Jahre und / oder Monate ausgewählt werden können, um die Daten (dann eben für das ganze Jahr, oder einen Monat) anzuzeigen und mit einem Monat - oder Jahr zu vergleichen.

    Nun habe ich die Tageseinnahmen von 3 Jahren eingetragen, also ca. 800 Stück und die Ausführung der Anzeige der Daten für ein Jahr, dauert ca. 30 Sekunden.
    6 Jahre habe ich noch vor mir, bis ich auf Stand Heute bin und es kommen ja noch Einnahmen dazu, das macht mir Angst...

    Ich habe jetzt die Hoffnung, dass mein Code einfach schlecht ist und dieser verbessert werden kann, um die Performance zu steigern.
    Da ich diesen Code jedoch sinnvoll finde, fällt mir keine Verbesserung dazu ein. Der Code ist großzügig kommentiert und die Variablennamen sollten selbstsprechend sein (cih hoffe es zumindest) :)

    Hier der Code für die Anzeige der Jahresumsätze

    VB.NET-Quellcode

    1. Private Sub BTNYear_Click(sender As Object, e As EventArgs) Handles BTNYear.Click
    2. FillYear
    3. End Sub
    4. 'Funktion zur Jahresauswertung
    5. Private Sub FillYear()
    6. 'Prüfen ob Eingaben in ComboBoxen numerisch sind
    7. Dim year As Integer
    8. Dim yearcomp As Integer
    9. 'Prüfen ob cbyear numerisch ist
    10. If Not Integer.TryParse(CBYear.Text, year) Then
    11. Exit Sub
    12. End If
    13. 'Prüfen ob cbcompyear numerisch ist
    14. If Not Integer.TryParse(CBCompare.Text, yearcomp) Then
    15. Exit Sub
    16. End If
    17. 'DGV löschen
    18. DelDGV()
    19. 'Spalten anlegen
    20. 'erste Spalte für Datumswerte anlegen
    21. DGVEvaluation.Columns.Add("clmDate", "Datum")
    22. Dim groupcount As Integer = DtsSettings.ProductGroup.Count
    23. Dim Groupname As String
    24. 'entsprechend Spalten anlegen
    25. For i = 0 To groupcount - 1
    26. 'Name aus BindingSource lesen
    27. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(i), DataRowView).Row, DtsSettings.ProductGroupRow)
    28. Groupname = ProductGroup.Name
    29. 'Spalte für jede Warengruppe anlegen
    30. DGVEvaluation.Columns.Add("clm" & Groupname, Groupname)
    31. Next
    32. 'Spalten für Tageseinnahme und Kunden anlegen
    33. With DGVEvaluation
    34. .Columns.Add("clmTotalIncome", "gesamt")
    35. .Columns.Add("clmCustomers", "Kunden")
    36. End With
    37. 'Zeilen für Monate anlegen
    38. Dim DGVColumnCount As Integer = DGVEvaluation.ColumnCount
    39. DGVEvaluation.Rows.Add("Januar")
    40. DGVEvaluation.Rows.Add("Februar")
    41. DGVEvaluation.Rows.Add("März")
    42. DGVEvaluation.Rows.Add("April")
    43. DGVEvaluation.Rows.Add("Mai")
    44. DGVEvaluation.Rows.Add("Juni")
    45. DGVEvaluation.Rows.Add("Juli")
    46. DGVEvaluation.Rows.Add("August")
    47. DGVEvaluation.Rows.Add("September")
    48. DGVEvaluation.Rows.Add("Oktober")
    49. DGVEvaluation.Rows.Add("November")
    50. DGVEvaluation.Rows.Add("Dezember")
    51. DGVEvaluation.Rows.Add("")
    52. DGVEvaluation.Rows.Add("gesamt")
    53. DGVEvaluation.Rows.Add("%")
    54. Dim ArrIncomeMonth(0 To 12, 0 To groupcount) As Double
    55. Dim ArrCustomers(0 To 11) As Integer
    56. Dim ArrIncomeYear(0 To groupcount) As Double
    57. Dim CustomersTotal As Integer
    58. Dim DateSelected As Date
    59. Dim numberofdays As Integer
    60. Dim tempdate As Date
    61. '1. Schleife für jeden Monat - für das aktuelle Jahr
    62. For i = 1 To 12
    63. DateSelected = Date.Parse("01." & i & "." & year)
    64. numberofdays = Integer.Parse(DateTime.DaysInMonth(year, i).ToString)
    65. 'Schleife für jeden Tag des Monats
    66. For j = 0 To numberofdays - 1
    67. 'ausgewähltes Jahr
    68. tempdate = DateSelected.AddDays(j)
    69. 'Datum in den Einnahmen suchen
    70. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = tempdate)
    71. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    72. 'Kunden speichern
    73. ArrCustomers(i - 1) += IncomeRow.CustomerCount
    74. For k = 0 To groupcount - 1 'Schleife durch Product Group DataTable
    75. 'Name aus BindingSource lesen
    76. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(k), DataRowView).Row, DtsSettings.ProductGroupRow)
    77. Groupname = ProductGroup.Name
    78. 'Warengruppenumsatz für Datum ermitteln und in Array addieren
    79. Dim ProductGroupRow = DtsSettings.Distribution_Table.SingleOrDefault(Function(x) x.DailyIncomeRow._Date.Date = tempdate AndAlso x.ProductGroupRow.Name = Groupname)
    80. If ProductGroupRow Is Nothing Then Continue For
    81. ArrIncomeMonth(i - 1, k) += CDbl(ProductGroupRow.ProductGroupIncome / 100)
    82. Next
    83. 'Gesamtumsatz ins Array schreiben
    84. ArrIncomeMonth(i - 1, groupcount) += CDbl(IncomeRow.DailyIncome / 100)
    85. Next
    86. 'Umsätze addieren und Daten ins DGV schreiben
    87. For L = 0 To groupcount
    88. ArrIncomeYear(L) += ArrIncomeMonth(i - 1, L)
    89. DGVEvaluation.Rows(i - 1).Cells(L + 1).Value = ArrIncomeMonth(i - 1, L).ToString("#,##0.00")
    90. Next
    91. 'Kunden ins DGV schreiben
    92. DGVEvaluation.Rows(i - 1).Cells(DGVColumnCount - 1).Value = ArrCustomers(i - 1).ToString
    93. Next
    94. 'Gesamtumsatz ins DGV schreiben
    95. For i = 0 To groupcount
    96. DGVEvaluation.Rows(13).Cells(i + 1).Value = ArrIncomeYear(i).ToString("#,##0.00")
    97. Next
    98. 'Gesamtkunden eintragen
    99. For i = 0 To 11
    100. CustomersTotal += ArrCustomers(i)
    101. Next
    102. DGVEvaluation.Rows(13).Cells(DGVColumnCount - 1).Value = CustomersTotal.ToString
    103. '2. Schleife für jeden Monat - für das vergleichsjahr
    104. Dim DateComp As Date
    105. Dim numberofdayscomp As Integer
    106. Dim ArrIncomeMonthComp(0 To 12, 0 To groupcount) As Double
    107. Dim ArrCustomersComp(0 To 11) As Integer
    108. Dim arrIncomeYearComp(0 To groupcount) As Double
    109. For i = 1 To 12
    110. DateComp = Date.Parse("01." & i & "." & yearcomp)
    111. numberofdayscomp = Integer.Parse(DateTime.DaysInMonth(yearcomp, i).ToString)
    112. 'Schleife für jeden Tag des Monats
    113. For j = 0 To numberofdayscomp - 1
    114. 'ausgewähltes Jahr
    115. tempdate = DateComp.AddDays(j)
    116. 'Datum in den Einnahmen suchen
    117. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = tempdate)
    118. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    119. 'Kunden speichern
    120. ArrCustomersComp(i - 1) += IncomeRow.CustomerCount
    121. For k = 0 To groupcount - 1 'Schleife durch Product Group DataTable
    122. 'Name aus BindingSource lesen
    123. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(k), DataRowView).Row, DtsSettings.ProductGroupRow)
    124. Groupname = ProductGroup.Name
    125. 'Warengruppenumsatz für Datum ermitteln und in Array addieren
    126. Dim ProductGroupRow = DtsSettings.Distribution_Table.SingleOrDefault(Function(x) x.DailyIncomeRow._Date.Date = tempdate AndAlso x.ProductGroupRow.Name = Groupname)
    127. If ProductGroupRow Is Nothing Then Continue For
    128. ArrIncomeMonthComp(i - 1, k) += CDbl(ProductGroupRow.ProductGroupIncome / 100)
    129. Next
    130. 'Gesamtumsatz ins Array schreiben
    131. ArrIncomeMonthComp(i - 1, groupcount) += CDbl(IncomeRow.DailyIncome / 100)
    132. Next
    133. 'Umsätze addieren und Daten ins DGV schreiben
    134. For L = 0 To groupcount
    135. arrIncomeYearComp(L) += ArrIncomeMonthComp(i - 1, L)
    136. Next
    137. Next
    138. 'Leerzeile und Zeile fürs Vergleichsjahr anlegen
    139. DGVEvaluation.Rows.Add("")
    140. DGVEvaluation.Rows.Add(DateComp.ToString("yyyy"))
    141. 'Umsätze aus Vergleichsjahr ins DGV schreiben
    142. For L = 0 To groupcount
    143. DGVEvaluation.Rows(16).Cells(L + 1).Value = arrIncomeYearComp(L).ToString("#,##0.00")
    144. Next
    145. 'Kunden ins DGV schreiben
    146. Dim CustomersTotalComp As Integer
    147. For i = 0 To 11
    148. CustomersTotalComp += ArrCustomersComp(i)
    149. Next
    150. DGVEvaluation.Rows(16).Cells(DGVColumnCount - 1).Value = CustomersTotalComp.ToString
    151. '% ausrechnen - Kunden
    152. DGVEvaluation.Rows(14).Cells(DGVColumnCount - 1).Value = Math.Round(((CustomersTotal - CustomersTotalComp) / CustomersTotalComp) * 100, 2).ToString("0.00") & " %"
    153. '& ausrechnene - Warengruppen
    154. For i = 0 To groupcount
    155. DGVEvaluation.Rows(14).Cells(i + 1).Value = Math.Round(((ArrIncomeYear(i) - arrIncomeYearComp(i)) / arrIncomeYearComp(i)) * 100, 2).ToString("0.00") & " %"
    156. Next
    157. 'Gesamtkunden vergleichen und ggf. blau färben
    158. If CustomersTotal > CustomersTotalComp Then
    159. For i = 13 To 14
    160. With DGVEvaluation
    161. .Rows(i).Cells(DGVColumnCount - 1).Style.ForeColor = Color.Blue
    162. .Rows(i).Cells(DGVColumnCount - 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    163. End With
    164. Next
    165. End If
    166. 'Gesamumsätze vergleichen und ggf blau färben
    167. For i = 0 To groupcount
    168. If ArrIncomeYear(i) > arrIncomeYearComp(i) Then
    169. For j = 13 To 14
    170. With DGVEvaluation
    171. .Rows(j).Cells(i + 1).Style.ForeColor = Color.Blue
    172. .Rows(j).Cells(i + 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    173. End With
    174. Next
    175. End If
    176. Next
    177. 'Monatsumsätze vergleichen und ggf. blau färben
    178. For i = 0 To 11
    179. For j = 0 To groupcount
    180. If ArrIncomeMonth(i, j) > ArrIncomeMonthComp(i, j) Then
    181. With DGVEvaluation
    182. .Rows(i).Cells(j + 1).Style.ForeColor = Color.Blue
    183. .Rows(i).Cells(j + 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    184. End With
    185. End If
    186. Next
    187. Next
    188. 'Monatskunden vergleichen und ggf. blau färben
    189. For i = 0 To 11
    190. If ArrCustomers(i) > ArrCustomersComp(i) Then
    191. With DGVEvaluation
    192. .Rows(i).Cells(DGVColumnCount - 1).Style.ForeColor = Color.Blue
    193. .Rows(i).Cells(DGVColumnCount - 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    194. End With
    195. End If
    196. Next
    197. 'DGV Spalten formatieren
    198. FormatDGV(DGVColumnCount)
    199. 'Größe von DGV und Form anpassen
    200. ChangeSizes(DGVColumnCount)
    201. End Sub
    202. 'Sub zum löschen des DGV
    203. Private Sub DelDGV()
    204. With DGVEvaluation
    205. .Rows.Clear()
    206. For i As Integer = .ColumnCount - 1 To 0 Step -1
    207. .Columns.RemoveAt(i)
    208. Next i
    209. End With
    210. End Sub


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub FormatDGV(DGVColumnCount As Integer)
    2. DGVEvaluation.DefaultCellStyle.Font = New Font("Microsoft Sans Serif", 12)
    3. For L = 1 To DGVColumnCount - 1
    4. With DGVEvaluation.Columns(L)
    5. .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
    6. .AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
    7. .SortMode = DataGridViewColumnSortMode.NotSortable
    8. End With
    9. Next
    10. With DGVEvaluation.Columns(DGVColumnCount - 2)
    11. .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
    12. .AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
    13. .SortMode = DataGridViewColumnSortMode.NotSortable
    14. End With
    15. With DGVEvaluation.Columns(0)
    16. .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
    17. .AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
    18. .SortMode = DataGridViewColumnSortMode.NotSortable
    19. End With
    20. With DGVEvaluation.Columns(DGVColumnCount - 3)
    21. .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
    22. .AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
    23. .SortMode = DataGridViewColumnSortMode.NotSortable
    24. End With
    25. 'DGV Header formatieren
    26. With DGVEvaluation.ColumnHeadersDefaultCellStyle
    27. .Alignment = DataGridViewContentAlignment.MiddleCenter
    28. .Font = New Font("Microsoft Sans Serif", 12)
    29. End With
    30. End Sub
    31. Private Sub ChangeSizes(DGVColumnCount As Integer)
    32. 'Größe des DGV anpassen
    33. DGVEvaluation.Width = DGVEvaluation.Columns.Cast(Of DataGridViewColumn).Sum(Function(x) x.Width) + 2
    34. DGVEvaluation.Height = DGVEvaluation.Rows.Cast(Of DataGridViewRow).Sum(Function(x) x.Height) + DGVEvaluation.ColumnHeadersHeight
    35. DGVEvaluation.Columns(DGVColumnCount - 1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
    36. 'Größe der Form anpassen
    37. Dim border As Integer = Integer.Parse(((Me.Size.Width - Me.ClientSize.Width) / 2).ToString)
    38. Dim header As Integer = Me.Size.Height - Me.ClientSize.Height - border
    39. Dim NewFormWidth = DGVEvaluation.Width + border * 2 + 30
    40. If NewFormWidth > 738 Then Me.Width = NewFormWidth
    41. Me.Height = DGVEvaluation.Height + border + header + 80
    42. End Sub


    und dann hier noch der Code für die Monate. Das ganze läuft in einer annehmbaren Zeit durch, allerdings ist ja hier auch die Datenmenge kleiner.
    Da ich diesen Code aber nach dem gleichen Schema wie die Jahresumsätze erstellt habe, ist er (hoffentlich) auch verbesserungswürdig:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Funktion für Monatsauswertung
    2. Private Sub FillMonth()
    3. 'DGV löschen
    4. DelDGV()
    5. 'erste Spalte für Datumswerte anlegen
    6. DGVEvaluation.Columns.Add("clmDate", "Datum")
    7. 'Anzahl der Warengruppen ermitteln
    8. Dim GroupCount As Integer
    9. GroupCount = DtsSettings.ProductGroup.Count
    10. Dim Groupname As String
    11. 'Schleife durch jede Warengruppe
    12. For i = 0 To GroupCount - 1
    13. 'Name aus BindingSource lesen
    14. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(i), DataRowView).Row, DtsSettings.ProductGroupRow)
    15. Groupname = ProductGroup.Name
    16. 'Spalte für jede Warengruppe anlegen
    17. DGVEvaluation.Columns.Add("clm" & Groupname, Groupname)
    18. Next
    19. 'Spalten für Tageseinnahme und Kunden anlegen
    20. With DGVEvaluation
    21. .Columns.Add("clmTotalIncome", "gesamt")
    22. .Columns.Add("clmCustomers", "Kunden")
    23. .Columns.Add("clmHeader", "")
    24. .Columns.Add("cmlpcs", "pro Kopf")
    25. End With
    26. 'DGV Spalten formatieren
    27. Dim DGVColumnCount As Integer = DGVEvaluation.ColumnCount
    28. FormatDGV(DGVColumnCount)
    29. 'Start und Enddatum aus Comboboxen ermitteln
    30. Dim StartDate As Date
    31. Dim Numberofdays As Integer
    32. Dim StartDateComp As Date
    33. Dim NumberofdaysComp As Integer
    34. If Not GetDates(StartDate, Numberofdays, StartDateComp, NumberofdaysComp) Then
    35. MessageBox.Show("ungültige Datumsauswahl")
    36. Exit Sub
    37. End If
    38. 'Schleife durch jeden Tag des Monats
    39. Dim TempDate As Date
    40. Dim indexcounter As Integer = -1
    41. Dim ArrGroupIncome(0 To GroupCount - 1) As Double
    42. Dim Totalincome As Double
    43. Dim Dailyincome As Double
    44. Dim TotalCustomers As Integer
    45. Dim DailyCustomers As Integer
    46. Dim AmountOfIncomeDays As Integer = 0
    47. For i = 0 To Numberofdays - 1
    48. 'Datum um einen Tag erhöhen
    49. TempDate = StartDate.AddDays(i)
    50. 'Datum in den Einnahmen suchen
    51. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = TempDate)
    52. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    53. 'Wenn gefunden: Datum in Listview schreiben
    54. DGVEvaluation.Rows.Add(IncomeRow._Date.ToString("ddd dd.MM"))
    55. AmountOfIncomeDays += 1
    56. indexcounter += 1
    57. 'und Warengruppeneinnahmen aus DTS pulen
    58. For j = 0 To GroupCount - 1 'Schleife durch Product Group DataTable
    59. 'Name aus BindingSource lesen
    60. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(j), DataRowView).Row, DtsSettings.ProductGroupRow)
    61. Groupname = ProductGroup.Name
    62. 'Warengruppenumsatz für Datum ermitteln und in Listview eintragen
    63. Dim ProductGroupRow = DtsSettings.Distribution_Table.SingleOrDefault(Function(x) x.DailyIncomeRow._Date.Date = TempDate AndAlso x.ProductGroupRow.Name = Groupname)
    64. If ProductGroupRow Is Nothing Then Continue For
    65. Dim Income As Double
    66. Income = CDbl(ProductGroupRow.ProductGroupIncome / 100)
    67. DGVEvaluation.Rows(indexcounter).Cells(j + 1).Value = Income.ToString("#,##0.00")
    68. 'Umsatz in Array addieren
    69. ArrGroupIncome(j) += Income
    70. Next
    71. 'Tagesumsatz (gesamt) und Kunden eintragen und Gesamtzahlen errechnen
    72. Dailyincome = CDbl(IncomeRow.DailyIncome / 100)
    73. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 4).Value = Dailyincome.ToString("#,##0.00")
    74. Totalincome += Dailyincome
    75. DailyCustomers = IncomeRow.CustomerCount
    76. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 3).Value = DailyCustomers.ToString
    77. TotalCustomers += DailyCustomers
    78. Next
    79. 'Leerzeile anlegen
    80. DGVEvaluation.Rows.Add()
    81. 'Zeile für Gesamtumsätze anlegen
    82. DGVEvaluation.Rows.Add("gesamt")
    83. indexcounter += 2
    84. 'Gesamtumsätze für jede Warengruppe eintragen
    85. For k = 0 To GroupCount - 1
    86. DGVEvaluation.Rows(indexcounter).Cells(k + 1).Value = ArrGroupIncome(k).ToString("#,##0.00")
    87. Next
    88. 'Gesamtumsatz Tage eintragen
    89. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 4).Value = Totalincome.ToString("#,##0.00")
    90. 'Gesamtkunden eintragen
    91. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 3).Value = TotalCustomers.ToString
    92. 'Pro Kopf Umsatz
    93. Dim PCS = 0.00
    94. If TotalCustomers > 0 Then PCS = Totalincome / TotalCustomers
    95. DGVEvaluation.Rows(0).Cells(DGVColumnCount - 2).Value = "pro Kopf"
    96. DGVEvaluation.Rows(0).Cells(DGVColumnCount - 1).Value = PCS.ToString("0.00")
    97. 'Kundenschnitt
    98. Dim CustAvg = TotalCustomers / AmountOfIncomeDays
    99. DGVEvaluation.Rows(1).Cells(DGVColumnCount - 2).Value = "Kundenschnitt"
    100. DGVEvaluation.Rows(1).Cells(DGVColumnCount - 1).Value = CustAvg.ToString("0.00")
    101. 'Umsätze aus Vergleichsjahr suchen
    102. Dim ArrGroupIncomeComp(0 To GroupCount - 1) As Double
    103. Dim TotalIncomeComp As Double
    104. Dim TotalCustomersComp As Integer
    105. Dim AmountOfCompDays As Integer = 0
    106. For i = 0 To NumberofdaysComp - 1
    107. 'Datum um einen Tag erhöhen
    108. TempDate = StartDateComp.AddDays(i)
    109. 'Datum in den Einnahmen suchen
    110. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = TempDate)
    111. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    112. AmountOfCompDays += 1
    113. 'Warengruppeneinnahmen aus DTS pulen
    114. For j = 0 To GroupCount - 1 'Schleife durch Product Group DataTable
    115. 'Name aus BindingSource lesen
    116. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(j), DataRowView).Row, DtsSettings.ProductGroupRow)
    117. Groupname = ProductGroup.Name
    118. 'Warengruppenumsatz für Datum ermitteln
    119. Dim ProductGroupRow = DtsSettings.Distribution_Table.SingleOrDefault(Function(x) x.DailyIncomeRow._Date.Date = TempDate AndAlso x.ProductGroupRow.Name = Groupname)
    120. If ProductGroupRow Is Nothing Then Continue For
    121. Dim Income As Double
    122. Income = CDbl(ProductGroupRow.ProductGroupIncome / 100)
    123. 'Umsatz in Array addieren
    124. ArrGroupIncomeComp(j) += Income
    125. Next
    126. 'Tagesumsatz (gesamt) und Kunden eintragen und Gesamtzahlen errechnen
    127. Dailyincome = CDbl(IncomeRow.DailyIncome / 100)
    128. TotalIncomeComp += Dailyincome
    129. DailyCustomers = IncomeRow.CustomerCount
    130. TotalCustomersComp += DailyCustomers
    131. Next
    132. 'Zeile für Vergleichen anlegen
    133. indexcounter += 1
    134. DGVEvaluation.Rows.Add("%")
    135. '% für jede Warengruppe eintragen
    136. For i = 0 To GroupCount - 1
    137. DGVEvaluation.Rows(indexcounter).Cells(i + 1).Value = Math.Round(((ArrGroupIncome(i) - ArrGroupIncomeComp(i)) / ArrGroupIncomeComp(i)) * 100, 2).ToString("0.00") & " %"
    138. Next
    139. '% für Tagesumsatz eintragen
    140. Dim DailyIncomeCompare As Double = Math.Round(((Totalincome - TotalIncomeComp) / TotalIncomeComp) * 100, 2)
    141. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 4).Value = DailyIncomeCompare.ToString("0.00") & " %"
    142. '% für Kunden eintragen
    143. Dim Customercompare As Double = Math.Round(((TotalCustomers - TotalCustomersComp) / TotalCustomersComp) * 100, 2)
    144. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 3).Value = Customercompare.ToString("0.00") & " %"
    145. 'Umsätze und % blau färben, wenn > 100
    146. If Customercompare > 0 Then
    147. With DGVEvaluation
    148. .Rows(indexcounter).Cells(DGVColumnCount - 3).Style.ForeColor = Color.Blue
    149. .Rows(indexcounter).Cells(DGVColumnCount - 3).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    150. .Rows(indexcounter - 1).Cells(DGVColumnCount - 3).Style.ForeColor = Color.Blue
    151. .Rows(indexcounter - 1).Cells(DGVColumnCount - 3).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    152. End With
    153. End If
    154. If DailyIncomeCompare > 0 Then
    155. With DGVEvaluation
    156. .Rows(indexcounter).Cells(DGVColumnCount - 4).Style.ForeColor = Color.Blue
    157. .Rows(indexcounter).Cells(DGVColumnCount - 4).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    158. .Rows(indexcounter - 1).Cells(DGVColumnCount - 4).Style.ForeColor = Color.Blue
    159. .Rows(indexcounter - 1).Cells(DGVColumnCount - 4).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    160. End With
    161. End If
    162. For i = 0 To ArrGroupIncome.Count - 1
    163. If ArrGroupIncome(i) > ArrGroupIncomeComp(i) Then
    164. With DGVEvaluation
    165. .Rows(indexcounter).Cells(i + 1).Style.ForeColor = Color.Blue
    166. .Rows(indexcounter).Cells(i + 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    167. .Rows(indexcounter - 1).Cells(i + 1).Style.ForeColor = Color.Blue
    168. .Rows(indexcounter - 1).Cells(i + 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    169. End With
    170. End If
    171. Next
    172. 'Leerzeile anlegen
    173. DGVEvaluation.Rows.Add()
    174. indexcounter += 2
    175. 'Zeile für Umsätze aus Vergleichsjahr anlegen
    176. DGVEvaluation.Rows.Add(StartDateComp.ToString("yyyy"))
    177. 'Gesamtumsätze für jede Warengruppe eintragen
    178. For i = 0 To GroupCount - 1
    179. DGVEvaluation.Rows(indexcounter).Cells(i + 1).Value = ArrGroupIncomeComp(i).ToString("#,##0.00")
    180. Next
    181. 'Gesamtumsatz Tage eintragen
    182. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 4).Value = TotalIncomeComp.ToString("#,##0.00")
    183. 'Gesamtkunden eintragen
    184. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 3).Value = TotalCustomersComp.ToString
    185. 'Pro Kopf Umsatz
    186. Dim PCSComp = 0.00
    187. If TotalCustomersComp > 0 Then PCSComp = TotalIncomeComp / TotalCustomersComp
    188. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 2).Value = "pro Kopf"
    189. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 1).Value = PCSComp.ToString("0.00")
    190. 'Kundenschnitt
    191. DGVEvaluation.Rows.Add()
    192. indexcounter += 1
    193. Dim CustAvgComp As Double = 0
    194. If AmountOfCompDays > 0 Then CustAvgComp = TotalCustomersComp / AmountOfCompDays
    195. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 2).Value = "Kundenschnitt"
    196. DGVEvaluation.Rows(indexcounter).Cells(DGVColumnCount - 1).Value = CustAvgComp.ToString("0.00")
    197. 'Größe von DGV und Form anpassen
    198. ChangeSizes(DGVColumnCount)
    199. End Sub
    Bilder
    • DataSet.jpg

      393,8 kB, 1.920×1.080, 109 mal angesehen
    • Form.jpg

      269,85 kB, 1.920×1.080, 114 mal angesehen

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

    Boah, sorry, aber 600 Zeilen zu optimieren ist jetzt nicht gerade eine Aufgabe, die man nebenbei macht. Und ob da viele Lust drauf haben, ist noch ein anderes Thema.
    Daher allgemeine Tipps: vor dem 1. Beschreiben des DGVs ein DeinDGV.SuspendLayout, nach dem letzten Beschreiben ein DeinDGV.ResumeLayout.
    Ansonsten könntest Du auch probieren, die Daten in eine DataTable zu schreiben und diese entweder direkt oder über eine BindingSource ans DGV dranzuhängen, also das DGV nicht direkt zu beschreiben.
    Und dann ist noch die Frage, wie das DGV eingestellt ist. Bei Columns.Width AllCells oder AllCellsWithoutHeader einzustellen ist sehr performancelastig.
    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.
    Teste mal wo genau der Zeitfresser sitzt.

    Werden Methoden mehrfach aufgerufen?
    -> Redundanzen entfernen bzw. verhindern.

    Also auf den ersten Blick sehe ich haufenweise Schleifen.
    -> lassen sich diese (ganz oder teilweise) zusammenlegen?

    Zudem finden irgendwelche Formatierungen im Grid statt.
    -> läuft es schneller ohne diese Formatierung.

    Ich nehme gerne Debug.Print() und lasse mir ausgeben an welcher Stelle ich mich befinde und einen Zeitstempel. Dann programm einmal durchlaufen lassen und schauen was so passiert ist.

    Du hast da echt üblen Spaghetticode. Lagere einzelne Elemente in separate Methoden aus. Macht das ganze übersichtlicher.
    "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
    Hallo ihr beiden
    Danke für eure Antworten (die ich aus Zeitgründen bisher nur überflogen habe)

    Ich erwarte natürlich keinesfalls fertigen Code oder eine Mega optimierung.
    Da ich mir einfach nur nicht vorstellen kann, dass die Aufgabe des Codes so lange Zeit (30 Sek. bei 800 Einträgen) in Anspruch nehmen kann (denn die Daten sind ja nunmal im Ram),
    habe ich die Vermutung, dass mein Code sinntechnisch riesen Bockmist ist - der für euch beim überfliegen ersichtlich ist.
    Naja, mein erster Optimierungsansatz: Du hast ne Sub, die über 200 Zeilen lang ist. Da den überblick zu behalten und Zeitmessungen anzusetzen, dürfte schwierig werden. Ist jetzt kein immer zu erstrebenden Verhalten, aber meine Subs sind meist ≪ 20 Zeilen groß, weil ich jede Aufgabe, die man extrahieren kann, in ne eigene Sub auslagere. Nicht nur als Außenstehender denkt man sich, bevor man sowas anfängt: Was soll das bitte bringen? Keine Sorge, das denk ich mir auch häufiger. Aber was sich dann für Verbesserungen in Code und Übersicht ergeben, sieht man erst im Nachhinein - und die Ergebnisse überraschen mich häufiger zum Positiven.
    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.
    jo, ich kann mich auch nur so ganz allgemein hin äussern.
    Stichwort "PerformanceFresser finden".
    Da gibts ja Tools für im VS - aber muss man erst lernen, anzumachen, und dann, die Ergebnisse richtig zu interpretieren.

    Ein anderer Ansatz ist, Codeteile auszukommentieren, und zu gucken, obs dann signifikant schneller ist.

    Sicherlich ist auch hierbei eine Modularisierung höchst hilfreich (wurde ja schon gesagt).
    Soho.
    Ich habe meine Prozedur nun in mehrere Teilschritte unterteilt.
    Das sieht jetzt so aus:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub FillYear()
    2. 'Prüfen ob Eingaben in ComboBoxen numerisch sind
    3. Dim year As Integer
    4. Dim yearcomp As Integer
    5. 'Prüfen ob cbyear numerisch ist
    6. If Not Integer.TryParse(CBYear.Text, year) Then
    7. Exit Sub
    8. End If
    9. 'Prüfen ob cbcompyear numerisch ist
    10. If Not Integer.TryParse(CBCompare.Text, yearcomp) Then
    11. Exit Sub
    12. End If
    13. Dim groupcount = DtsSettings.ProductGroup.Count
    14. 'DGV löschen
    15. DelDGV()
    16. 'Spalten im DGV anlegen
    17. DrawDGV(groupcount)
    18. Dim DGVColumnCount = DGVEvaluation.ColumnCount
    19. 'Daten für das erste Jahr ins DataSet schreiben - und angelegte Variablen ByRef füllen
    20. Dim CustomersTotal As Integer
    21. Dim ArrIncomeMonth(0 To 12, 0 To groupcount) As Double
    22. Dim ArrCustomers(0 To 11) As Integer
    23. Dim ArrIncomeYear(0 To groupcount) As Double
    24. WriteDataFirstYear(groupcount, year, DGVColumnCount, CustomersTotal, ArrIncomeMonth, ArrCustomers, ArrIncomeYear)
    25. 'Werte für das Vergleichsjahr ins DataSet schreiben - und angelegte Variablen ByRef füllen
    26. Dim CustomersTotalComp As Integer
    27. Dim arrIncomeYearComp(0 To groupcount) As Double
    28. Dim ArrIncomeMonthComp(0 To 12, 0 To groupcount) As Double
    29. Dim ArrCustomersComp(0 To 11) As Integer
    30. WriteDataCompYear(groupcount, yearcomp, DGVColumnCount, CustomersTotalComp, arrIncomeYearComp, ArrIncomeMonthComp, ArrCustomersComp)
    31. 'Umsatzentwicklung in % ins DGV schreiben und Zuwachs blau färben
    32. CompareYears(DGVColumnCount, CustomersTotal, CustomersTotalComp, groupcount, ArrIncomeYear, arrIncomeYearComp, ArrIncomeMonth, ArrIncomeMonthComp, ArrCustomers, ArrCustomersComp)
    33. 'DGV Spalten formatieren
    34. FormatDGV(DGVColumnCount)
    35. 'Größe von DGV und Form anpassen
    36. ChangeSizes(DGVColumnCount)
    37. End Sub

    Die sind teilweise noch recht lang (haben aber auch viel zu tun). Es ist aber schonmal sehr viel übersichtlicher geworden.
    Auch wenn ich irgendwie daran zweifel, dass ich mich bei meiner "Zerstückelung" mit Ruhm bekleckern werde - aber der Code läuft!
    Ich habe dann nach folgendem Schema die Zeitfresser entlarvt:

    VB.NET-Quellcode

    1. Starttime = System.DateTime.Now
    2. 'DGV löschen
    3. DelDGV()
    4. Debug.Print("DelDGV")
    5. Debug.Print((System.DateTime.Now.Subtract(Starttime)).ToString)


    Das lieferte mir ein eindeutiges Ergebnis:
    Spoiler anzeigen
    Prüfungszeit ob Jahre numerisch sind
    00:00:00.0029707
    DelDGV
    00:00:00.0039864
    DrawDGV
    00:00:00.0289225
    WriteDataFirstYear
    00:00:12.8993392
    WriteDataCompYear
    00:00:15.0770617
    CompareYears
    00:00:00.0576991
    FormatDGV
    00:00:00.0708113
    ChangeSizes
    00:00:00.0059842

    Das Löschen, Erstellen und Formatieren des DGV nimmt keine Zeit in Anspruch. Es ist die Funktion der Prozedur an sich.
    WriteDataFirstYear0 und WriteDataCompYear sind die Zeitfresser.
    Beide Subs machen ziemlich das gleiche - alle Umsätze des angegebenen Jahres aus dem DGV pulen (WriteDataCompYear - vergleicht noch die beiden Jahre)

    Hier also die Zeitfresser Sub - an der mir aber nichts zu verschnellern einfällt :(

    Edit: Da die Sub ja jetzt aus dem Zusammenhang genommen wird.
    Ich speichere die Umsätze und Kunden in Arrays, sowohl in dieser Sub, als auch in der Folgesub, welche die Daten aus dem Vergleichsjahr holt, damit ich diese dann Vergleichen kann.
    Die Vergleichssub habe ich unten hinterm Spoiler versteckt (nur des Verständnisses wegen)

    VB.NET-Quellcode

    1. Private Sub WriteDataFirstYear(groupcount As Integer, year As Integer, DGVColumnCount As Integer, ByRef Customerstotal As Integer,
    2. ByRef ArrIncomeMonth(,) As Double, ByRef ArrCustomers() As Integer, ByRef ArrIncomeYear() As Double)
    3. Dim DateSelected As Date
    4. Dim numberofdays As Integer
    5. Dim tempdate As Date
    6. Dim Groupname As String
    7. '1. Schleife für jeden Monat - für das aktuelle Jahr
    8. For i = 1 To 12
    9. DateSelected = Date.Parse("01." & i & "." & year)
    10. numberofdays = Integer.Parse(DateTime.DaysInMonth(year, i).ToString)
    11. 'Schleife für jeden Tag des Monats
    12. For j = 0 To numberofdays - 1
    13. 'ausgewähltes Jahr
    14. tempdate = DateSelected.AddDays(j)
    15. 'Datum in den Einnahmen suchen
    16. Dim IncomeRow = DtsSettings.DailyIncome.FirstOrDefault(Function(x) x._Date.Date = tempdate)
    17. If IncomeRow Is Nothing Then Continue For 'Wenn nicht gefunden, nächster Durchgang
    18. 'Kunden speichern
    19. ArrCustomers(i - 1) += IncomeRow.CustomerCount
    20. For k = 0 To groupcount - 1 'Schleife durch Product Group DataTable
    21. 'Name aus BindingSource lesen
    22. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(k), DataRowView).Row, DtsSettings.ProductGroupRow)
    23. Groupname = ProductGroup.Name
    24. 'Warengruppenumsatz für Datum ermitteln und in Array addieren
    25. Dim ProductGroupRow = DtsSettings.Distribution_Table.SingleOrDefault(Function(x) x.DailyIncomeRow._Date.Date = tempdate AndAlso x.ProductGroupRow.Name = Groupname)
    26. If ProductGroupRow Is Nothing Then Continue For
    27. ArrIncomeMonth(i - 1, k) += CDbl(ProductGroupRow.ProductGroupIncome / 100)
    28. Next
    29. 'Gesamtumsatz ins Array schreiben
    30. ArrIncomeMonth(i - 1, groupcount) += CDbl(IncomeRow.DailyIncome / 100)
    31. Next
    32. 'Umsätze addieren und Daten ins DGV schreiben
    33. For L = 0 To groupcount
    34. ArrIncomeYear(L) += ArrIncomeMonth(i - 1, L)
    35. DGVEvaluation.Rows(i - 1).Cells(L + 1).Value = ArrIncomeMonth(i - 1, L).ToString("#,##0.00")
    36. Next
    37. 'Kunden ins DGV schreiben
    38. DGVEvaluation.Rows(i - 1).Cells(DGVColumnCount - 1).Value = ArrCustomers(i - 1).ToString
    39. Next
    40. 'Gesamtumsatz ins DGV schreiben
    41. For i = 0 To groupcount
    42. DGVEvaluation.Rows(13).Cells(i + 1).Value = ArrIncomeYear(i).ToString("#,##0.00")
    43. Next
    44. 'Gesamtkunden eintragen
    45. For i = 0 To 11
    46. Customerstotal += ArrCustomers(i)
    47. Next
    48. DGVEvaluation.Rows(13).Cells(DGVColumnCount - 1).Value = Customerstotal.ToString
    49. End Sub


    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Sub zum Vergleichen der beiden Jahre
    2. Private Sub CompareYears(DGVColumnCount As Integer, CustomersTotal As Integer, CustomersTotalComp As Integer, groupcount As Integer, arrincomeyear() As Double,
    3. arrIncomeYearComp() As Double, arrIncomeMonth(,) As Double, arrIncomeMonthComp(,) As Double, arrCustomers() As Integer,
    4. arrCustomersComp() As Integer)
    5. '% ausrechnen - Kunden
    6. DGVEvaluation.Rows(14).Cells(DGVColumnCount - 1).Value = Math.Round(((CustomersTotal - CustomersTotalComp) / CustomersTotalComp) * 100, 2).ToString("0.00") & " %"
    7. '% ausrechnene - Warengruppen
    8. For i = 0 To groupcount
    9. DGVEvaluation.Rows(14).Cells(i + 1).Value = Math.Round(((arrincomeyear(i) - arrIncomeYearComp(i)) / arrIncomeYearComp(i)) * 100, 2).ToString("0.00") & " %"
    10. Next
    11. 'Gesamtkunden vergleichen und ggf. blau färben
    12. If CustomersTotal > CustomersTotalComp Then
    13. For i = 13 To 14
    14. With DGVEvaluation
    15. .Rows(i).Cells(DGVColumnCount - 1).Style.ForeColor = Color.Blue
    16. .Rows(i).Cells(DGVColumnCount - 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    17. End With
    18. Next
    19. End If
    20. 'Gesamumsätze vergleichen und ggf blau färben
    21. For i = 0 To groupcount
    22. If arrincomeyear(i) > arrIncomeYearComp(i) Then
    23. For j = 13 To 14
    24. With DGVEvaluation
    25. .Rows(j).Cells(i + 1).Style.ForeColor = Color.Blue
    26. .Rows(j).Cells(i + 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    27. End With
    28. Next
    29. End If
    30. Next
    31. 'Monatsumsätze vergleichen und ggf. blau färben
    32. For i = 0 To 11
    33. For j = 0 To groupcount
    34. If arrIncomeMonth(i, j) > arrIncomeMonthComp(i, j) Then
    35. With DGVEvaluation
    36. .Rows(i).Cells(j + 1).Style.ForeColor = Color.Blue
    37. .Rows(i).Cells(j + 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    38. End With
    39. End If
    40. Next
    41. Next
    42. 'Monatskunden vergleichen und ggf. blau färben
    43. For i = 0 To 11
    44. If arrCustomers(i) > arrCustomersComp(i) Then
    45. With DGVEvaluation
    46. .Rows(i).Cells(DGVColumnCount - 1).Style.ForeColor = Color.Blue
    47. .Rows(i).Cells(DGVColumnCount - 1).Style.Font = New Font("Microsoft Sans Serif", 12, FontStyle.Bold)
    48. End With
    49. End If
    50. Next
    51. End Sub

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

    Äh keine Ahnung warum, aber wenn ich die 4 Codezeilen, in denen das DGV in der Sub beschrieben wird auskommentiere, dauert die Ausführung 0,1 Sekunde länger.
    Aber das liegt wohl an dem was Windows im Hintergrund so treibt. Bei beiden Ausführungen habe ich natürlich keine weiteren Programme im Hintergrund laufen, außer Chrome.
    normal
    00:00:12.4492368
    auskommentiert
    00:00:12.5555194

    Ich glaube das Problem ist das Datensammeln an sich.
    Ich habe mal die Zeit gemessen, wie lange es dauert die äußerste Schleife laufen zu lassen (also For i = 1 to 12) (die Monate)
    Spoiler anzeigen
    Schleifendurchlauf 1 Dauer:00:00:01.4132186
    Gesamtdauer: 00:00:01.4132186
    Schleifendurchlauf 2 Dauer:00:00:01.2945741
    Gesamtdauer: 00:00:02.7077927
    Schleifendurchlauf 3 Dauer:00:00:01.3454371
    Gesamtdauer: 00:00:04.0532298
    Schleifendurchlauf 4 Dauer:00:00:01.3274515
    Gesamtdauer: 00:00:05.3806813
    Schleifendurchlauf 5 Dauer:00:00:01.3454382
    Gesamtdauer: 00:00:06.7261195
    Schleifendurchlauf 6 Dauer:00:00:01.4052404
    Gesamtdauer: 00:00:08.1313599
    Schleifendurchlauf 7 Dauer:00:00:01.4461326
    Gesamtdauer: 00:00:09.5774925
    Schleifendurchlauf 8 Dauer:00:00:01.4621292
    Gesamtdauer: 00:00:11.0396217
    Schleifendurchlauf 9 Dauer:00:00:01.3653498
    Gesamtdauer: 00:00:12.4049715
    Schleifendurchlauf 10 Dauer:00:00:00.1785231
    Gesamtdauer: 00:00:12.5834946
    Schleifendurchlauf 11 Dauer:00:00:00.0039881
    Gesamtdauer: 00:00:12.5874827
    Schleifendurchlauf 12 Dauer:00:00:00.0039877
    Gesamtdauer: 00:00:12.5914704

    Für November (11) und Dezember (12) habe ich die Daten gelöscht. Für diese Monate gibt es also keine Einnahmen.
    Nun sind ja anderthalb Sekunden denke ich für das was da passiert ok. Aber 12 mal 1,5 Sekunden (und das zwei mal) ergibt dann wohl Wartezeit :(

    Danach habe ich dann die Zeit gemessen, die die Innere Schleife benötigt (For j = 0 to numberofdays (also die Tage des Monats) - für den Fall i = 1
    Spoiler anzeigen
    Schleifendurchlauf 1 Dauer:00:00:00.0668639
    Gesamtdauer: 00:00:00.0668639
    Schleifendurchlauf 2 Dauer:00:00:00.0608682
    Gesamtdauer: 00:00:00.1277321
    Schleifendurchlauf 3 Dauer:00:00:00.0598389
    Gesamtdauer: 00:00:00.1875710
    Schleifendurchlauf 4 Dauer:00:00:00.0538915
    Gesamtdauer: 00:00:00.2414625
    Schleifendurchlauf 6 Dauer:00:00:00.0538999
    Gesamtdauer: 00:00:00.2953624
    Schleifendurchlauf 7 Dauer:00:00:00.0559078
    Gesamtdauer: 00:00:00.3512702
    Schleifendurchlauf 8 Dauer:00:00:00.0608705
    Gesamtdauer: 00:00:00.4121407
    Schleifendurchlauf 9 Dauer:00:00:00.0558941
    Gesamtdauer: 00:00:00.4680348
    Schleifendurchlauf 10 Dauer:00:00:00.0578810
    Gesamtdauer: 00:00:00.5259158
    Schleifendurchlauf 11 Dauer:00:00:00.0578758
    Gesamtdauer: 00:00:00.5837916
    Schleifendurchlauf 13 Dauer:00:00:00.0548546
    Gesamtdauer: 00:00:00.6386462
    Schleifendurchlauf 14 Dauer:00:00:00.0518613
    Gesamtdauer: 00:00:00.6905075
    Schleifendurchlauf 15 Dauer:00:00:00.0568842
    Gesamtdauer: 00:00:00.7473917
    Schleifendurchlauf 16 Dauer:00:00:00.0578775
    Gesamtdauer: 00:00:00.8052692
    Schleifendurchlauf 17 Dauer:00:00:00.0748280
    Gesamtdauer: 00:00:00.8800972
    Schleifendurchlauf 18 Dauer:00:00:00.0568467
    Gesamtdauer: 00:00:00.9369439
    Schleifendurchlauf 20 Dauer:00:00:00.0558886
    Gesamtdauer: 00:00:00.9928325
    Schleifendurchlauf 21 Dauer:00:00:00.0578815
    Gesamtdauer: 00:00:01.0507140
    Schleifendurchlauf 22 Dauer:00:00:00.0598836
    Gesamtdauer: 00:00:01.1105976
    Schleifendurchlauf 23 Dauer:00:00:00.0578819
    Gesamtdauer: 00:00:01.1684795
    Schleifendurchlauf 24 Dauer:00:00:00.0668222
    Gesamtdauer: 00:00:01.2353017
    Schleifendurchlauf 25 Dauer:00:00:00.0738288
    Gesamtdauer: 00:00:01.3091305
    Schleifendurchlauf 27 Dauer:00:00:00.0620770
    Gesamtdauer: 00:00:01.3712075
    Schleifendurchlauf 28 Dauer:00:00:00.0538928
    Gesamtdauer: 00:00:01.4251003
    Schleifendurchlauf 29 Dauer:00:00:00.0588797
    Gesamtdauer: 00:00:01.4839800
    Schleifendurchlauf 30 Dauer:00:00:00.0568812
    Gesamtdauer: 00:00:01.5408612


    Also müsste ich doch irgendwie die Zugriffe aufs DataSet verringern um wirklich Zeit zu sparen. Oder gibt es noch eine andere Möglichkeit?
    Denn Zugriffe reduzieren kann ich ja irgendwie nicht.

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

    Ich hab jetzt mal mit Zufallszahlen/-werten gearbeitet und lass mir für 2020 366 DailyIncome-Datensätze erstellen. Dazu jeweils 1 Distribution_Table-Eintrag. Mit Erstellung und Auswertung braucht das Ganze bei mir gefühlte 0,1 Sekunden.
    btw: ziemlich viele ByRef-Parameter. Dass Du ner Function Datenpakete oder Tuples zurückgeben kannst, weißt Du?
    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
    Magst du das Mal hochladen?
    Nur als Vergleich, um sicherzugehen, dass die Performance meines Rechners schuld ist.
    Das mit den Datenpaketen und Tuples wusste ich nicht. Werde ich mir Mal zu Gemüte führen.
    Ist die Verwendung von vielen byrefs problematisch?
    jo, da kann man sich wohl auf die geschachtelte Daten-Sammel-Schleife konzentrieren.
    Mir sieht das aus wie ein Join von DailyInCome mit DistributionTable mit ProductGroup innerhalb eines Jahres und nur ausgewählte ProductGroups.

    Wenns das ist kann man das in paar Zeilen ziemlich effizient mit Linq formulieren, und ohne .SingleOrDefault() - was nämlich eine Tabelle jedesmal komplett durchsuchen muss.
    Wieviele Datensätze beinhalten die Tabellen DailyIncome und Distribution_Table, und wie gross ist groupcount (so durchschnittlich)?

    Also man müsste mit 3 DatenMengen-Scans auskommen:
    1. die betreffenden DailyIncome.Id - Werte suchen
    2. die betreffenden ProductGroup.Id - Werte suchen
    3. die Distribution_Table-Datensätze suchen, die auf Elemente beider vorgenannten Ids verweisen.
    Also das wäre jetzt handgestrickt und mit Hashsets machbar, wie gesagt: vlt. lässts sich mit Linq eleganter formulieren bei gleicher oder besserer Performance.

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

    Im Anhang.
    Das mit ByRef: Sollte man nicht als erweiterten Return-Value missbrauchen. Es gibt Fälle, in denen ein Parameter reingeht und verändert wieder rauskommen muss. Aber wenn ein leeres Objekt/Array/whatever erst in der Prozedur mit Daten befüllt wird, dann stimmt normalerweise was nicht. Desweiteren ist klar, dass Deine Prozedur immer noch mehr macht als eine Sache, Stichwort SRP (ja, man kann es auch auf Prozeduren erweitern). Sie rechnet Sachen zusammen, befüllt Variablen und schreibt Daten ins DGV.
    Dateien
    • TestApp.zip

      (60,73 kB, 70 mal heruntergeladen, zuletzt: )
    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.
    Hi,

    ich verwende ausschließlich DB's (Access ;SqL-Server etc...)
    ich verstehe diese Dts Datasets nicht ganz, ünterstützen diese nicht das PIvot Format?
    der ganze schreit doch nach einer PIVOT-Tabelle aus allen Daten

    @DerSmurf... zeige doch mal ein Bild wie es auszieht wenn die Daten geladen sind.

    hier habe ich mal versucht mit DataTable eine Gruppierung nach Jahr;Artikel die Gesamtverkäufe
    anzuzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Public Class Form4
    3. Private dt As New DataTable()
    4. Private distinctTableData As New DataTable()
    5. Private Sub Form4_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    6. dt.Columns.AddRange(New DataColumn(3) {New DataColumn("Jahr", GetType(Integer)), _
    7. New DataColumn("Artikel", GetType(String)), _
    8. New DataColumn("Einzelpreis", GetType(Double)), _
    9. New DataColumn("Menge", GetType(Double))})
    10. distinctTableData.Columns.AddRange(New DataColumn(4) {New DataColumn("Jahr", GetType(Integer)), _
    11. New DataColumn("Artikel", GetType(String)), _
    12. New DataColumn("Einzelpreis", GetType(Double)), _
    13. New DataColumn("Menge", GetType(Double)), _
    14. New DataColumn("Gesamt", GetType(Double))})
    15. 'Beispiel Daten zur Ansicht
    16. dt.Rows.Add(2019, "Roller", 55.15, 4)
    17. dt.Rows.Add(2019, "Roller", 55.15, 8)
    18. dt.Rows.Add(2018, "Fahrad", 116.33, 5)
    19. dt.Rows.Add(2019, "Fahrad", 116.33, 15)
    20. dt.Rows.Add(2021, "Rollschuhe", 16.33, 4)
    21. dt.Rows.Add(2021, "Rollschuhe", 16.33, 14)
    22. dt.Rows.Add(2020, "Roller", 55.15, 8)
    23. dt.Rows.Add(2019, "Roller", 55.15, 4)
    24. dt.Rows.Add(2019, "Roller", 55.15, 8)
    25. dt.Rows.Add(2018, "Fahrad", 116.33, 5)
    26. dt.Rows.Add(2018, "Fahrad", 116.33, 15)
    27. dt.Rows.Add(2021, "Rollschuhe", 16.33, 40)
    28. dt.Rows.Add(2021, "Rollschuhe", 16.33, 24)
    29. dt.Rows.Add(2019, "Roller", 55.15, 18)
    30. DataGridView1.DataSource = dt
    31. DataGridView1.Sort(DataGridView1.Columns(0), ListSortDirection.Ascending)
    32. End Sub
    33. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    34. 'gruppiere in distinctTableData die Werte aus dt.Datatable
    35. Dim distinctTableData As DataTable = dt.DefaultView.ToTable(True, "Jahr", "Artikel", "Einzelpreis")
    36. DataGridView2.Columns.Add("Jahr", "Jahr")
    37. DataGridView2.Columns.Add("Artikel", "Artikel")
    38. DataGridView2.Columns.Add("Einzelpreis", "Einzelpreis")
    39. DataGridView2.Columns.Add("Menge", "Menge")
    40. DataGridView2.Columns.Add("Gesamt", "Gesamt")
    41. For Each row As DataRow In distinctTableData.Rows
    42. 'Jahr Gruppieren
    43. Dim GroupToSum As String = CStr(row("Jahr"))
    44. Dim n As String = String.Format("Jahr='{0}'", GroupToSum)
    45. 'den Einzeilpreis wollen wir nicht summieren,
    46. 'sonder nur zeigen
    47. Dim ObjectArtikel As String = CStr(row("Artikel").ToString)
    48. Dim ObjectEinzelpreis As Double = CDbl(row("Einzelpreis").ToString)
    49. 'die Mengen Summieren die Vekauft wurden
    50. Dim SummeEinzelpreisImJahr As Double = CDbl(dt.Compute("SUM(Menge)".ToString, n))
    51. 'jetzt den Einzelpreis * die Mengen im Jahr
    52. Dim ObjectGesamt As Double = ObjectEinzelpreis * SummeEinzelpreisImJahr
    53. 'ausgabe in DGV
    54. DataGridView2.Rows.Add(GroupToSum, _
    55. ObjectArtikel, _
    56. ObjectEinzelpreis, _
    57. SummeEinzelpreisImJahr, _
    58. ObjectGesamt)
    59. Next
    60. End Sub
    61. End Class



    möchte den Thread nicht ausnutzen, aber wieso nicht eine PIVOT Lösung?
    guck - ich hab das Sammeln der Distribution_Tables (was immer das sein soll, ein "Distribution_Table") in ein klein Methode gepackt:

    VB.NET-Quellcode

    1. Private Function GetDistributionTables(year As Integer, groupCount As Integer) As IEnumerable(Of Distribution_TableRow)
    2. Dim dt0 = New Date(year, 1, 1), dt1 = dt0.AddYears(1)
    3. Dim productGroups = Enumerable.Range(0, groupCount).Select(Function(k) DirectCast(DirectCast(ProductGroupBindingSource(k), DataRowView).Row, ProductGroupRow))
    4. Return From distTbl In productGroups.SelectMany(Function(x) x.GetDistribution_TableRows)
    5. Let dt = distTbl.DailyIncomeRow._Date
    6. Where dt >= dt0 AndAlso dt < dt1 Select distTbl
    7. End Function
    Das ist jetzt ohne Linq-Join, sondern mehr klassisch mittels der Verknüpfungen, die das typDataset bereitstellt.
    Wäre auch interessant, die Performance mit einer Linq-Join-Alternative zu vergleichen.

    Es gibt alle Distribution_TableRows zurück im angegebenen Zeitraum, die einer der angegebenen ProductGroups angehören.
    Somit alle Datensätze, deren Werte du irgendwie in dein DGV einfrickeln willst.
    Das weitere sollte - wenn richtig angefasst - also keinen Zeitverzug mehr ausmachen.



    Kasi schrieb:

    aber wieso nicht eine PIVOT Lösung?

    Zunächstmal weiss Ich nicht, ob ich hier der richtige bin, darauf zu antworten.
    Dann kenne ich das PIVOT-Feature nicht, und ob es das tun würde, was hier verlangt ist.
    Tatsächlich weiss ich garnet, was hier verlangt ist - ich finde es in diesem Thread nicht wirklich definiert. Das verlangt sei, alle Distribution_Tables eines Zeitraums und einer Gruppe von ProductGroups aufzusuchen, ist nur meine Vermutung, die ich dem gegebenen Code "ab-geraten" habe. Wozu das im weiteren gut sein soll, hab ich nicht durchdrungen.
    Weiters wird hier scheints mit typisiertem Dataset gearbeitet, bislang ohne Hinzuziehen von zusätzlichen (PIVOT-)Abfragen an eine Datenbank.
    In VB.Net - inklusive Linq und typDataset-Technologie - ist mir jedenfalls ein PIVOT-Feature nicht bekannt - es muss sich also um etwas aus dem SQL-Paradigma handeln.

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

    Huhu Ihr alle.
    Sorry, hatte heute über Tag keine Zeit ins Forum zu schauen, daher meine Antwort erst jetzt.
    @Kasi mach dir nix draus. Ich habe den "Mist" geschrieben und finde das ganze auch ein wenig verwirrend :o)
    Aber dafür sind wir ja alle da.

    @VaporiZed
    Dass ich die Sub noch weiter unterteilen kann (und wohl auch sollte) steht außer Frage.
    Allerdings ist mir hier kein Weg eingefallen, wie ich dies anstelle, ohne die eigentliche Sub zu sehr zu verfälschen.
    Denn mein Problem ist ja, dass das ganze zu lange dauert - wohl wegen der ganzen Schleifen. Wenn ich nun in einer Schleife die Daten sammel und dann in einer weiteren Sub, wiederum in einer (neuen) Schleife, die Daten ins DGV schreibe - ist das ja nicht besonders zweckdienlich.
    Deswegen gebe ich dir Recht, dass die Sub weiter aufgesplittet gehört, fand es aber der Lösung hier nicht zuträglich, aber ich werde es machen (isch schwör)
    Und! SORRY! So eine Beispielapp soll natürlich von mir kommen, und nicht vom Helfer.
    Da mache ich mich jetzt dran, und werde sie dann als Edit hier präsentieren. Denn deine Beispielapp entspricht nicht dem Original.

    @ErfinderDesRades
    Der Groupcount ist vor Programmstart unbekannt. Daher ist das DataSet so wie es ist. Sinn und Zweck ist, dass der User den groupcount und groupname so setzen kann, wie er lustig ist.
    In meinem Fall ist (und bleibt) der groupcount 8
    Aufgrund der unbekannten groupcount gibt es die Distribution Table die die Tageseinnahme für jede Group hält, verknüpft mit der DailyIncome Table, welche die Kundenzahl, sowie den Gesamtumsatz des Tages (und natürlich das enstprechende Datum) hält. Ich hoffe das ist so richtig erklärt. Die Idee für diese DataSet Struktur stammt vom @VaporiZed
    Dementsprechend sind die Datenmengen in der Distribution Table und in DailyIncome gleich.
    In meinem konkreten Fall jetzt vom 03.03.2011 bis zum 05.10.2013 (mehr habe ich nocht nicht eingetragen) - also ca. 800 Werte.
    Das ganze wird natürlich ausgebaut bis zum heutigen Tag (da gibt es ja logischerweise schon Tageseinnahmen) und dann kommt halt jeden Tag ein Tag dazu,
    Hätte ich also alle Einnahmen eingetragen, wären es 9 Jahre (ca. 300 Tage pro Jahr = 2700 Einträge).

    Edit:
    Die Demoapp habe ich hochgeladen. Diese entspricht genau dem Original. Die Stellen die ich ändern musste (z.B. speichern und laden des Dts) habe ich gekennzeichnet.
    Ich habe die xml mit 8 Warengruppen im Debug Ordner gelassen und einen Button, sowie zwei Textboxen zum erstellen der Daten im DataSet und Angabe des Startdatums (03.03.2011 in meinem Fall) und Menge der Tage die eingetragen werden sollen (ca. 850 in meinem Fall) hinzugefügt. Leider schaffe ich es nicht, die Sub von @VaporiZed zum erstellen dieser Daten so anzupassen, dass ich die entsprechenden Distribution Table Rows und Einnahmen für Warengruppen hinzufügen kann.
    Hier bräuchte ich einmal Hilfe:

    VB.NET-Quellcode

    1. Private Sub BTNAddData_Click(sender As Object, e As EventArgs) Handles BTNAddData.Click
    2. Dim AmountOfDays As Integer = Integer.Parse(TBAmountOfDays.Text)
    3. Dim Startdate As Date = Date.Parse(TBStartDate.Text)
    4. Dim Random As New Random
    5. For i = 0 To AmountOfDays - 1
    6. DtsSettings.DailyIncome.AddDailyIncomeRow(Startdate.AddDays(i), Random.Next(1000), CInt(Random.NextDouble() * 10000))
    7. DtsSettings.Distribution_Table.AddDistribution_TableRow(DtsSettings.DailyIncome(i), DtsSettings.ProductGroup(Random.Next(3)), CInt(Random.NextDouble() * 10000))
    8. Next
    9. End Sub
    Dateien

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

    Hmm - ich weiss nicht mehr, worums geht.
    In post#7 schien es noch um eine Sub WriteDataFirstYear() zu gehen, davon ist jetzt, wo ich dachte, ich hätte das (Performance-)Problem verstanden und gelöst, keine Rede mehr.

    Nun geht es um eine Sub BTNAddData_Click() und um eine Sub SaveIncome().
    Du sagst, du brauchst bei Sub BTNAddData_Click() Hilfe, aber was da passiert und was da passieren soll ist mir nicht klar.
    Und ich fürchte, der Thread geht noch ein bischen weiter, ich reime mir wieder was zusammen, was das Problem sein könnte, löse es, und dann ist wieder auf einmal von etwas ganz annerem die Rede.

    Vielleicht sollte ich mal 3 Tage abwarten und gucken, ob sich die Wirrsal vermehrt, oder ob gar iwas klarer wird...
    Ja du hast Recht. Ich bin vielleicht ein bisschen sprunghaft :)
    Also es geht immernoch um das Problem, aus post7 - die Sub WriteDataFirstYear.

    Ich dachte mir, es ist vielleicht angenehmer, wenn der TE eine Anwendung hochlädt , damit die Helfer sich nicht noch im VS was zusammenklicken müssen (so wie Vaporized) das getan hat.
    Da ich aber meine Originaldaten nicht hochladen möchte (weil es halt Originalumsätze) sind, entstand die sub BTNAddData_click.
    Diese soll nur ins DataSet der Beispielanwendung Daten eintragen, damit die Beispielanwendung auch einen Sinn hat.
    Also ab einem Datum (TBStartDate) eine bestimmte Menge Tage (TBAmountOfDays) eine Tageseinnahme und jeweils eine Einnahme für alle 8 Warengruppen zu erstellen.
    Daran bin ich aber gescheitert, sodass ich nicht ohne Hilfe eine sinnvolle DemoApp hochladen kann.

    Ich habe den obigen Thread bearbeitet und die speichern sub entfernt.
    Bitte vergiss das einfach.
    Eins nach dem anderen :)
    Ich schwöre meine Sprunghaftigkeit abzulegen (bzw. es ernsthaft zu versuchen)

    Deine Fragen aus Post12 habe ich in obigen Post ebenfalls beantwortet, du sollst dir ja nix zusammenreimen zu müssen.

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

    gut - habich mir die Solution aus post#12 geladen - kompiliert nicht.
    Die Fehlerzeile auskommentiert, dann startet das, und eine Messagebox sagt mir:
    ---------------------------

    ---------------------------
    Es wurden noch keine Einnahmen gespeichert. Originalform würde nun schließen
    ---------------------------
    OK
    ---------------------------

    Nach Bestätigen geht ein Form auf:


    Was soll ich nun damit tun?
    In post#12 erwähnst du iwelche Daten - ich finde aber nur eine Data.xml folgenden Inhalts:
    Spoiler anzeigen

    XML-Quellcode

    1. <?xml version="1.0" standalone="yes"?>
    2. <DtsSettings xmlns="http://tempuri.org/DtsSettings.xsd">
    3. <ProductGroup>
    4. <ID>-1</ID>
    5. <Name>Kat1</Name>
    6. </ProductGroup>
    7. <ProductGroup>
    8. <ID>-2</ID>
    9. <Name>Kat2</Name>
    10. </ProductGroup>
    11. <ProductGroup>
    12. <ID>-3</ID>
    13. <Name>Kat3</Name>
    14. </ProductGroup>
    15. <ProductGroup>
    16. <ID>-4</ID>
    17. <Name>Kat4</Name>
    18. </ProductGroup>
    19. <ProductGroup>
    20. <ID>-5</ID>
    21. <Name>Kat5</Name>
    22. </ProductGroup>
    23. <ProductGroup>
    24. <ID>-6</ID>
    25. <Name>Kat6</Name>
    26. </ProductGroup>
    27. <ProductGroup>
    28. <ID>-7</ID>
    29. <Name>Kat7</Name>
    30. </ProductGroup>
    31. <ProductGroup>
    32. <ID>-8</ID>
    33. <Name>Kat8</Name>
    34. </ProductGroup>
    35. </DtsSettings>

    Du sagst - wenn ich recht versteh - Im Download die Sub WriteDataFirstYear() täte richtig arbeiten, aber zu langsam.
    Wie kriege ich die überhaupt ans arbeiten??

    Hab ich das überhaupt richtig verstanden: die Sub WriteDataFirstYear() in dem Download arbeitet richtig, aber zu langsam.
    Bitte bestätige mir auch nochmal ausdrücklich (oder korrigiere mich), dass ich das Problem dieses Threads damit richtig verstanden habe.