Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1340to1344
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Performance Probleme

Performance Probleme
18.12.2013 12:49:04
Sebastian
Hallo Zusammen!
ich habe eine komplexe Funktion erstellt zu deren Berechnung ein Breiten- und Höhenmaß als Bezug zu je einem Tabellenfeld als Eingabewerte benötigt werden.
In der Funktion wird jedoch ein Tabellenblatt mit derzeit 100 Zeilen und 7 Spaltenwerten durchsucht und die in jeder Zeilen enthaltenen Werte in der Funktion berechnet. Die Berechnung erfolgt nach Kriterien und durchläuf insgesamt pro Zeile je 4 If-Schleifen. Im Prinzip wird um einen Ausgabewert der Funktion zu erhalten, eine komplette Stückliste pro Funktionsverwendung berechnet. Ändert man nun einen der EingabeWerte der Funktion, werden natürlich alle Funktionen durchgerechnet, sofern ide Arbeitsmappe auf Automisches Berechnen eingestellt ist. In einer Preistabelle können schon mal 90-150 Funktionen mit unterschiedlichen Eingabewerten stehen. Das bedeutet eine entsprechende Anzahl von Berechnungen.
Ich bin auf folgende Überlegung gestoßen: 150 x 100 x 4 = 60.000 Berechnungen für ein Tabellenupdate.
Selbst mit 4 Prozessoren dauert so ein Update ca. 3-4 Minuten. Und es werden noch einige den Tabellen nachgestellte Berechnungen in die Arbeitsmappe eingebaut werden.
Ich habe die Berechnng der Tabelle bereits auf "manuell" im VBA Code gestellt.
In einem Thread hier im Forum habe ich jetzt gelesen, dass man die Berechnungszeit beschleunigen könnte, wenn ich die Daten, die in dem Tabellenblatt der Stückliste stehen, in ein Array einlese. Wie bekomme ich denn einen Bereich eines Tabellenblatts in ein Array und wie lese ich die Daten dort wieder aus?
Hier mal der Code der beiden Funktionen

Function KREUZWERT(Breite, Hoehe)
KREUZWERT = 0
For i = 1 To 100
'Datenzeile Einsammeln
For j = 1 To 10
DatenZeile(j) = Sheets(StueckL).Cells(i + 1, j).Text
Next j
'Werte korrekt Umwandeln
If DatenZeile(1)  "" Then
DatCaLBool = CInt(DatenZeile(1)) ' Berechnung Ja Nein = 1.Spalte
Else
GoTo ENDE:
End If
If DatenZeile(3)  "" Then
DatStueck = CDec(DatenZeile(3)) ' Anzahl der Teile Einlesen
Else
GoTo KeinWert:
End If
If DatenZeile(4)  "" Then
DatRaB = CDec(DatenZeile(4)) ' Anzahl der Teile pro Rahmenbreite einlesen
Else
GoTo KeinWert:
End If
If DatenZeile(5)  "" Then
DatOperand = CStr(DatenZeile(5)) ' Operand einlesen
Else
GoTo KeinWert:
End If
If DatenZeile(6)  "" Then
DatRaH = CDec(DatenZeile(6)) ' Anzahl der Teile pro Rahmenhöhe einlesen
Else
GoTo KeinWert:
End If
If DatenZeile(7)  "" Then
DatEHT = CStr(DatenZeile(7)) ' Berechnungseinheit "ST" "LM", "M2" - "M3" geht    _
_
_
nicht, weil die Dimensionen nicht zur Verfügung stehen
Else
GoTo KeinWert:
End If
If DatenZeile(8)  "" Then
DatPReis = CDec(DatenZeile(8)) ' Anzahl der Teile pro Rahmenhöhe einlesen
Else
GoTo KeinWert:
End If
'Berechnungsformel Aufrufen
a = Berechnung(DatCaLBool, DatStueck, DatRaB, DatOperand, DatRaH, DatEHT, DatPReis,  _
Breite, Hoehe)
KREUZWERT = KREUZWERT + a
a = 0
KeinWert:
Next i
ENDE:
End Function

Function Berechnung(CALBOOL, STUECK, RaB, OPERAND, RaH, EHT, PREIS, BerBReite, BerHoehe)
'Checken, ob überhaupt berechnet wird
If CALBOOL = 0 Then
Berechnung = 0
GoTo BerEnde:
End If
'Checken, obe es wirklich eine Addition ist
If OPERAND = "ADD" And EHT = "ST" Then
Berechnung = (STUECK * RaB + STUECK * RaH) * PREIS
End If
If OPERAND = "ADD" And EHT = "LM" Then
Berechnung = (STUECK * RaB * BerBReite / 1000 + STUECK * RaH * BerHoehe / 1000) * PREIS
End If
If OPERAND = "MUL" And EHT = "M2" Then
Berechnung = STUECK * RaB * (BerBReite / 1000) * RaH / (BerHoehe / 1000) * PREIS
End If
BerEnde:
End Function

Ich habe bisher nur immer mit Bezügen auf Tabellenblätter gearbeitet, weil ich mir das besser Vorstellen kann.
Noch eine Anmerkung: Ich habe das Programmieren mir selbst beigebracht.... vielleicht ist der Code deswegen nicht perfekt und nach "Regeln aufgebaut"... eher Spaghetti-CODE... wer also Optimierungen für mich hat... gerne lerne ich etwas...
Freue mich über jeden Tipp. Vielen Dank!

11
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Performance Probleme
18.12.2013 13:28:29
GuentherH
Hallo Sebastian,
überleg' doch auch mal, ob du die Zahl der zu berechnenden Zellen verringern kannst.
Andererseits können 10 Minuten Berechnungsdauer auch angemessen sein, wenn z.B. die Auswertung nur 1 Mal die Woche gestartet wird.
Beste Grüße,
Günther

AW: Performance Probleme
18.12.2013 17:29:53
Sebastian
Hallo GuentherH
Da die Stückliste variabel sein muss, habe ich nicht die Möglichkeit, die Anzahl der Zelen zu reduzieren.
Die Tabelle wird ggf. öfter als 1 mal am Tag berechnet, wenn sie im Gebrauch ist.
Meine Frage war die:
  • Wie lese ich ein Array schnell ein?

  • Wie verarbeite ich jede Datenzeile aus dem Array?

  • Bin gespannt...

    Anzeige
    AW: Performance Probleme
    19.12.2013 08:58:58
    bst
    Morgen,
       For i = 1 To 100
    For j = 1 To 10
    DatenZeile(j) = Sheets(StueckL).Cells(i + 1, j).Text
    

    erzeugt 1000 lesende Zugriffe auf die Tabelle.
    Nimm außerhalb der Schleife:
    DatenZeile = Sheets(StueckL).Cells(1,1).Resize(101, 10).Value
    
    das liest dann nur ein einziges Mal.
    Danach nimm überall wo Du bisher DatenZeile(n) benutzt hast jetzt DatenZeile(i+1,n)
    Lies dazu vielleicht auch mal: http://www.online-excel.de/excel/singsel_vba.php?f=47
    Wenn Du diese Function als Excel-Funktion benutzen willst (also aus einer Excel-Zelle her aufrufen) solltest Du das M.E. aber anders anfangen. Übergib dann den Bereich A1:J101 als Parameter an die Funktion, damit Excel selber bemerken kann wann neu berechnet werden muss.
    cu, Bernd

    Anzeige
    AW: Performance Probleme
    19.12.2013 10:04:34
    GuentherH
    Hallo Bernd,
    toller Artikel, habe bisher mit screenupdate nur so um den Faktor 2 bekommen.
    Dein Beispiel legt nochmal Faktor 20 drauf.
    Da bin ich doch gerne bereit, am Programmierstil zu arbeiten.
    Beste Grüße,
    Günther

    AW: Performance Probleme
    19.12.2013 11:22:46
    bst
    Hallo Günther,
    bitteschön, gerne.
    cu, Bernd

    AW: Performance Probleme
    19.12.2013 11:59:19
    Sebastian
    Hallo Bernd,
    Sorry, dass ich mich so spät melde... gestern wurde es Dank Programmierung spät...
    vielen Dank für das CODE Beispiel und den Hinweis darauf, wie ich es schneller hinbekomme.
    Das werde ich zuerst einmal ausprobieren.
    Ein Frage habe ich trotzdem noch... Du schreibst:
    Übergib dann den Bereich A1:J101 als Parameter an die Funktion, damit Excel selber bemerken kann wann neu berechnet werden muss.
    Wie meinst du denn das? Die Stückliste wird geändert, und dann muss manuell die Formel "KREUZWERT" neu berechnet weren, die dann die Stückliste aufruft und durchgeht. Meinst du das so, dass die Formel auch neu berechnet wird, wenn ich etwas an der Stückliste ändere? Das wäre ja nur ZU GENIAL :-)
    Da freue ich mich auf einen CODE-Ansatz, weil du mich da gerade in meinen Kenntnissen abgehängt hast.
    Aber das andere sieht auch richtig cool aus. Das Probiere ich gleich...
    MFG Sebastian

    Anzeige
    AW: Performance Probleme
    19.12.2013 12:31:26
    bst
    Hi,
    übergib den Bereich als Parameter an die Funktion, also z.B.:
    =KREUZWERT(Tabelle1!A1:J101, X1, Y1)
    
    oder besser lasse gleich noch die Überschrift weg (dann brauchst Du den i+1 nicht), also:
    =KREUZWERT(Tabelle1!A2:J101, X1, Y1)
    
    Dann berechnet Excel autmatisch neu wenn sich irgendeine der Zellen A1:J101 sowie X1 und Y1 ändert.
    Im Code nimm dann:
    Function KREUZWERT(Bereich As Range, Breite As Double, Hoehe As Double)
    Dim ar As Variant
    ar = Bereich.Value
    ' möglicherweise hier so einen Test zufügen:
    If UBound(ar, 1) 
    HTH, Bernd

    Anzeige
    AW: Performance Probleme
    19.12.2013 16:24:25
    Sebastian
    Hallo Bernd,
    Vielen Dank für deine Tipps.
    Also ich werde später nochmal darauf zurückkommen.
    Derzeit muss ich handwerklich andere Dinge in die Datei programmieren, damit ich sie ausliefern kann.
    Später muss ich mich dann um das Performance Tuning kümmern.
    Dann wirst du bestimmt nochmal von mir hören.
    Freundliche Grüße von Sebastian
    P.S.: Was ist "UBound"?

    AW: Performance Probleme
    19.12.2013 16:28:18
    bst
    Hi Sebastian,
    Ubound(ar) ODER Ubound(ar,1) liefert die obere Grenze der 1. Dimension eines Arrays (~=Anzahl Zeilen)
    Ubound(ar,2) liefert die obere Grenze der 2. Dimension eines Arrays (~=Anzahl Spalten)
    Lbound() liefert entsprechend die unteren Grenzen, die sind hier aber immer 1.
    cu, Bernd

    Anzeige
    AW: Performance Probleme
    19.12.2013 19:18:39
    Sebastian
    Hallo Rudi, Hallo Bernd,
    Also ich habe das ausprobiert. Die Geschichte mit dem Array hat Fantastisch Funktioniert.
    Ich habe die Stückliste sogar mit 100 in die Funktion Zeilen eingelesen und die BErechnung dauert keine 5 Sekunden im Vergleich zu knapp 2-3 Minuten vorhar.
    Das War ein SUPER TIPP!
    Danke an euch ALLE!

    Freundliche Grüße von Sebastian

    AW: Performance Probleme
    19.12.2013 16:48:35
    Rudi
    Hallo,
    teste mal:
    Function KREUZWERT(Bereich As Range, Breite, Hoehe)
    Dim DatenZeile, i As Long, j As Long, blnBerechne As Boolean
    Dim arrColumns
    Dim DatCaLBool As Integer
    Dim DatStueck As Single, DatRaB As Single, DatRaH As Single, DatPReis As Single
    Dim DatOperand As String, DatEHT As String
    arrColumns = Array(0, 1, 3, 4, 5, 6, 7, 8)
    DatenZeile = Bereich
    For i = 1 To UBound(DatenZeile)
    blnBerechne = True
    'Datenzeile Einsammeln
    For j = 1 To UBound(arrColumns)
    blnBerechne = blnBerechne And DatenZeile(i, arrColumns(j))  ""
    Next
    If blnBerechne Then
    DatCaLBool = CInt(DatenZeile(1)) ' Berechnung Ja Nein = 1.Spalte
    DatStueck = CDec(DatenZeile(3)) ' Anzahl der Teile Einlesen
    DatRaB = CDec(DatenZeile(4)) ' Anzahl der Teile pro Rahmenbreite einlesen
    DatOperand = CStr(DatenZeile(5)) ' Operand einlesen
    DatRaH = CDec(DatenZeile(6)) ' Anzahl der Teile pro Rahmenhöhe einlesen
    DatEHT = CStr(DatenZeile(7)) ' Berechnungseinheit "ST" "LM", "M2" - "M3" geht nicht, weil  _
    die Dimensionen nicht zur Verfügung stehen
    DatPReis = CDec(DatenZeile(8)) ' Anzahl der Teile pro Rahmenhöhe einlesen
    'Berechnungsformel Aufrufen
    KREUZWERT = KREUZWERT + _
    Berechnung(DatCaLBool, DatStueck, DatRaB, DatOperand, DatRaH, DatEHT, DatPReis, Breite,  _
    Hoehe)
    End If
    Next i
    End Function
    

    Gruß
    Rudi
    Anzeige

    Beliebteste Forumthreads (12 Monate)

    Anzeige

    Beliebteste Forumthreads (12 Monate)

    Anzeige
    Anzeige
    Anzeige