Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
968to972
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
968to972
968to972
Aktuelles Verzeichnis
Verzeichnis Index
Verzeichnis Index
Übersicht Verzeichnisse
Inhaltsverzeichnis

Benutzerdef. Fkt zu langsam

Benutzerdef. Fkt zu langsam
16.04.2008 22:03:24
Helena
Hallo liebe Excel-Fans,
brauche mal wieder Eure Hilfe.
Ich habe eine mehrere MB große Excel-Datei mit Daten, und eine Reihe von Auswertungen, die auf diese Daten zugreifen.
Für diese Auswertungen brauche ich immer wieder Summewenn mit bis zu 5 Kriterien.
Um die Pflege zu erleichtern, habe ich die Funktion mySummewenn geschrieben.
Leider arbeitet diese Funktion nicht besonders schnell, mittlerweile habe ich die Antwortzeiten von 5-10 Sec. :(
Ich habe nicht viel Ahnung von VBA.
Kann mir jemand sagen, wie ich diese Funktion optimieren kann?
Die Input-Kriterien müssen aber auf jeden Fall unverändert bleiben, denn die Anpassung würde einen Riesenaufwand bedeuten.
Hier ein Auszug aus der Datei incl. benutzerdef. Funktion.
https://www.herber.de/bbs/user/51628.xls

10
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Benutzerdef. Fkt zu langsam
16.04.2008 22:21:00
Fred
Hi,
viel ist da nicht drin:
Events ausschalten, Sreenupdating aus, Berechnung manuell
mfg Fred

AW: Benutzerdef. Fkt zu langsam
16.04.2008 23:13:35
Reinhard
Hi Helena,
schau mal hier: http://de.wikibooks.org/wiki/VBA_in_Excel_-_Grundlagen:_Code-Optimierung#Array-Formeln
vielleicht kann man das was basteln, mir grad zu aufwendig, aber einer der profis hier, z.B. deine riesen If abfrage oder so als eine Excelformel irgendwo auf einem Hoilfsblatt eintragen, runterkopieren, dann die Ergebnisse wieder zurück nach vba oder so.
Ich stelle mal deshalb die Frage auf noch offen.
Aber ich habe da noch etwas gedacht,du hast doch da diese zigfache If-Abfrage, alle sind mit OR verknüpft.
Kannst du das umschreiben auf AND !?
Excel wertet immer die ganze If-Zeile aus, egal ob schon das erste nicht stimmt
Also bei
If a=b AND 1=1 Then
wird auch 1=1 ausgewertet, dann erst das If verlassen, obwohl das sinnlos ist da ja a=b schon falsch ist.
Das "AND" gäbe einen gewaltigen Turboschub für deinen Code, schau mal hier auf die Zeiten:
Bei mir braucht das eine 0,141 s, das andere 0,016 s ! Liegt natürlich am PC, Rechnerauslastung usw.
Der Code (sorry, hatte keine Lust die ganzen Ifs einzurücken*gg*)

Option Explicit
Sub test()
Dim N, t
t = Timer
For N = 1 To 100000
If N = 5 And N = 5 And N = 5 And N = 5 And N = 5 And N = 5 And N = 5 And N = 5 Then
End If
Next N
MsgBox Timer - t
t = Timer
For N = 1 To 100000
If N = 5 Then
If N = 5 Then
If N = 5 Then
If N = 5 Then
If N = 5 Then
If N = 5 Then
If N = 5 Then
If N = 5 Then
End If
End If
End If
End If
End If
End If
End If
End If
Next N
MsgBox Timer - t
End Sub

Gruß
Reinhard

Anzeige
AW: Benutzerdef. Fkt zu langsam
16.04.2008 23:37:21
Josef
Hallo Helena,
die Funktion ist für die Katz. Das lässt sich über SUMMENPRODUKT() lösen.
Benutzerdefinierte Funktionen sind nun mal viel langsamer als Excelfunktionen und wenn darin auch noch mit Schleifen geabreitet wird, dann erst recht.

Gruß Sepp



AW: Benutzerdef. Fkt zu langsam
17.04.2008 08:32:31
Schnee
Hi Helena,
ich habe dir mal die Summenprodukt-Variante eingebaut:
https://www.herber.de/bbs/user/51639.xls
Wenn du den genutzten Bereichen entsprechende Namen zuweist wird die Formel natürlich sehr viel übersichtlicher.
Mit Bereich.Verschieben kannst du diese dann sogar dynamisch gestallten.
Beste Grüße,
Schnee

Anzeige
AW: Benutzerdef. Fkt zu langsam
17.04.2008 17:24:00
Helena
Hi,
und Danke für eure Antworten.
Es hat aber einen Grund, warum die benutzerdefinierte Fkt. verwendet wird und nicht das Summenprodukt:
- Der Datenbereich ist sehr unübersichtlich (8 Blätter mit jeweils bis zu 70 Spalten) und die Reihenfolge der Spalten kann sich ändern, da Befüllung aus der Datenbank mit VBA. Nur die Spalten-Namen bleiben immer gleich.
- Die Auswertungen umfassen mehrere DINA4-Seiten, und werden immer wieder bearbeitet/ergänzt.
Deshalb ist es wichtig, eine Funktion zu haben, mit der Pflege und Bug-Suche einfach ist. Außerdem ist die Datei mittlerweile so groß geworden, dass die Umstellung auf Summenprodukt oder andere benutzerdefinierte Funktion einen unvertretbaren Aufwand nach sich ziehen würde.
Mit anderen Worten: Ich brauche einen Tipp, wie ich den bestehenden VBA-Code optimieren kann, OHNE Änderungen in der Excel-Datei machen zu müssen.
Hat jemand eine Idee?

Anzeige
AW: Benutzerdef. Fkt zu langsam
18.04.2008 08:25:00
Schnee
Hi nochmal,
wenn es unbedingt in VBA alleine gelöst werden soll versuche es mal so:
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
...am Anfang der Funktion einfügen und:
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
End With
...ans Ende.
Sollte das auch nicht helfen, könntest du mit Application.Calculation = xlCalculationManual in die Workbook_Open Routine einfügen und müssten dann mit Hilfe des .Calculate Befehls in der jeweiligen Worksheet_Change Routine nur die Zellen neu berechnen lassen, die tatsächlich neu brechnet werden müssen. Aus der Funktion müsste Application.Calculation dann wieder raus.
Alternativ könntest du natürlich auch zu jedem Zeitpunkt mit F9 das komplette Workbook neu berechnen lassen.
Diese Variante hat bei meinen Dokumenten teilweise die Berechnungszeiten von 60Sek auf 5Sek runtergeschraubt.
Beste Grüße,
Schnee

Anzeige
AW: Benutzerdef. Fkt zu langsam
18.04.2008 00:57:47
Daniel
Hi
prinziiell würde ich versuchen, solche Auswertungen mit Pivot-Tabelle zu machen, das geht sehr einfach ohne Programmierung und ist auch recht flexibel.
sollte sich die Pivot-Tabelle nicht anwenden lassen, so könnte man dein Marko noch in folgenden Punkten optimieren:
1. in einem "Wort zum Sonntag" wurde mal erklärt, daß Variablen, die als Zeilen- und Spalten-Nr in Range-Objekten verwendet werden, immer in LONGINTEGER umgerechnet werden.
daher sollten Variablen, die so verwendet werden, immer als LONG deklariert werden, da sie sonst zeitaufwendig umgewandelt werden müssen. Werden sie gleich als LONG deklariert, entfällt die Umwandlung.
Ok, der Zeitgewinn dürfte hier recht gering sein, aber so rein prinzipiell....
2. du führst pro Zeile jeweils 5 x 3 Stringvergleiche durch, davon sind aber immer 2 x 5 Vergleiche für jede Zeile gleich.
diese könntest du vorab abprüfen und das Ergebnis in einer Boolschen Variable ablegen.
Im Schleifendruchlauf müsstest du dann nur noch diese Boolsche Variable prüfen, was deutlich schneller ist, als 2 Stringergleiche.
der Code dazu könnte so aussehen:

Option Explicit
Const alle As String = "(Alle)"
Public Function mySummewenn(ByVal SummeSpalte As String, Bereich As Range, _
Optional ParameterName_1 As String, Optional ParameterWert_1 As String, _
Optional ParameterName_2 As String, Optional ParameterWert_2 As String, _
Optional ParameterName_3 As String, Optional ParameterWert_3 As String, _
Optional ParameterName_4 As String, Optional ParameterWert_4 As String, _
Optional ParameterName_5 As String, Optional ParameterWert_5 As String)
Dim anzahlSpalten As Long
Dim anzahlZeilen As Long
Dim intHelp As Long
Dim parameterSpaltenindex_1 As Long
Dim parameterSpaltenindex_2 As Long
Dim parameterSpaltenindex_3 As Long
Dim parameterSpaltenindex_4 As Long
Dim parameterSpaltenindex_5 As Long
 Dim Prüfung_1 As Boolean
Dim Prüfung_2 As Boolean
Dim Prüfung_3 As Boolean
Dim Prüfung_4 As Boolean
Dim Prüfung_5 As Boolean
Dim mySumme As Single
Dim summeSpaltenindex As Long
Dim IndexLetzteNichtleereZeile As Long
anzahlSpalten = Bereich.Columns.Count
anzahlZeilen = Bereich.Rows.Count
mySumme = 0
On Error Resume Next
For intHelp = 1 To anzahlSpalten
If Bereich(1, intHelp) = ParameterName_1 Then parameterSpaltenindex_1 = intHelp
If Bereich(1, intHelp) = ParameterName_2 Then parameterSpaltenindex_2 = intHelp
If Bereich(1, intHelp) = ParameterName_3 Then parameterSpaltenindex_3 = intHelp
If Bereich(1, intHelp) = ParameterName_4 Then parameterSpaltenindex_4 = intHelp
If Bereich(1, intHelp) = ParameterName_5 Then parameterSpaltenindex_5 = intHelp
If Bereich(1, intHelp) = SummeSpalte Then summeSpaltenindex = intHelp
Next
 Prüfung_1 = (ParameterName_1 = "" Or ParameterWert_1 = alle)
Prüfung_2 = (ParameterName_2 = "" Or ParameterWert_2 = alle)
Prüfung_3 = (ParameterName_3 = "" Or ParameterWert_3 = alle)
Prüfung_4 = (ParameterName_4 = "" Or ParameterWert_4 = alle)
Prüfung_5 = (ParameterName_5 = "" Or ParameterWert_5 = alle)
For intHelp = 2 To anzahlZeilen
If Bereich(intHelp, parameterSpaltenindex_1) = ParameterWert_1 OrPrüfung_1 Then
If Bereich(intHelp, parameterSpaltenindex_2) = ParameterWert_2 OrPrüfung_2 Then
If Bereich(intHelp, parameterSpaltenindex_3) = ParameterWert_3 Or Prüfung_3  _
Then
If Bereich(intHelp, parameterSpaltenindex_4) = ParameterWert_4 Or Prüfung_4  _
_
_
Then
If Bereich(intHelp, parameterSpaltenindex_5) = ParameterWert_5 Or Prü _
fung_5 Then
mySumme = mySumme + CSng(Bereich(intHelp, summeSpaltenindex))
End If
End If
End If
End If
End If
Next
mySummewenn = mySumme
End Function
Gruß Daniel
ps für die vielen Leerzeilen kann ich leider nichts, die werden vom Edior automatisch eingefügt

Anzeige
AW: Benutzerdef. Fkt zu langsam
22.04.2008 18:58:59
Helena
Hallo,
vielen lieben Dank.
Ich habe gerade die Vorschläge von Schnee und Daniel getestet.
Ergebnis: keine Verbesserung. Jedesmal komme ich auf die Antwortzeiten von bis zu 17 Sek.
Die Excel-Datei hat übrigens den Zweck, alle möglichen Informationen tabellarisch und graphisch nach unterschiedlichsten Auswahlkriterien darzustellen: pro Kunde, pro Branche, pro Organisationseinheit, pro Monat etc.
Der Benutzer wählt einen Kunden / eine Organisationseinheiten etc. aus den entspr. DropDown-Listen und erhält (nach bis zu 17 sek. Wartezeit) alle benötigten Informationen auf einen Blick – vor allem eine Vielzahl an Graphiken. Es werden auch ein paar Pivot-Tabellen eingesetzt, aber sie können nicht alles :)
Viele Grüße
Helena

Anzeige
AW: Benutzerdef. Fkt zu langsam
22.04.2008 22:44:00
Daniel
Hi
wenn du so eine komplexe Datei hast, bist du dir dann sicher, daß diese Formel die alleinige Ursache ist?
oder könnten es noch andere sein?
Normale SVerweise und Zählenwenn oder Summewenn sind auch nicht gerade schnelle funktionen und können bei grossem Datenvolumen zu langen Rechenzeiten führen.
Gruß, Daniel.

AW: Benutzerdef. Fkt zu langsam
22.04.2008 19:21:00
Reinhard
Hallo Danuel,
jaja, immer diese bösen Editoren :-)
Kann es sein daß du das End-pre vergessen hast?
Gruß
Reinhard
Hi
prinziiell würde ich versuchen, solche Auswertungen mit Pivot-Tabelle zu machen, das geht sehr einfach ohne Programmierung und ist auch recht flexibel.
sollte sich die Pivot-Tabelle nicht anwenden lassen, so könnte man dein Marko noch in folgenden Punkten optimieren:
1. in einem "Wort zum Sonntag" wurde mal erklärt, daß Variablen, die als Zeilen- und Spalten-Nr in Range-Objekten verwendet werden, immer in LONGINTEGER umgerechnet werden.
daher sollten Variablen, die so verwendet werden, immer als LONG deklariert werden, da sie sonst zeitaufwendig umgewandelt werden müssen. Werden sie gleich als LONG deklariert, entfällt die Umwandlung.
Ok, der Zeitgewinn dürfte hier recht gering sein, aber so rein prinzipiell....
2. du führst pro Zeile jeweils 5 x 3 Stringvergleiche durch, davon sind aber immer 2 x 5 Vergleiche für jede Zeile gleich.
diese könntest du vorab abprüfen und das Ergebnis in einer Boolschen Variable ablegen.
Im Schleifendruchlauf müsstest du dann nur noch diese Boolsche Variable prüfen, was deutlich schneller ist, als 2 Stringergleiche.
der Code dazu könnte so aussehen:

Option Explicit
Const alle As String = "(Alle)"
Public Function mySummewenn(ByVal SummeSpalte As String, Bereich As Range, _
Optional ParameterName_1 As String, Optional ParameterWert_1 As String, _
Optional ParameterName_2 As String, Optional ParameterWert_2 As String, _
Optional ParameterName_3 As String, Optional ParameterWert_3 As String, _
Optional ParameterName_4 As String, Optional ParameterWert_4 As String, _
Optional ParameterName_5 As String, Optional ParameterWert_5 As String)
Dim anzahlSpalten As Long
Dim anzahlZeilen As Long
Dim intHelp As Long
Dim parameterSpaltenindex_1 As Long
Dim parameterSpaltenindex_2 As Long
Dim parameterSpaltenindex_3 As Long
Dim parameterSpaltenindex_4 As Long
Dim parameterSpaltenindex_5 As Long
 Dim Prüfung_1 As Boolean
Dim Prüfung_2 As Boolean
Dim Prüfung_3 As Boolean
Dim Prüfung_4 As Boolean
Dim Prüfung_5 As Boolean
Dim mySumme As Single
Dim summeSpaltenindex As Long
Dim IndexLetzteNichtleereZeile As Long
anzahlSpalten = Bereich.Columns.Count
anzahlZeilen = Bereich.Rows.Count
mySumme = 0
On Error Resume Next
For intHelp = 1 To anzahlSpalten
If Bereich(1, intHelp) = ParameterName_1 Then parameterSpaltenindex_1 = intHelp
If Bereich(1, intHelp) = ParameterName_2 Then parameterSpaltenindex_2 = intHelp
If Bereich(1, intHelp) = ParameterName_3 Then parameterSpaltenindex_3 = intHelp
If Bereich(1, intHelp) = ParameterName_4 Then parameterSpaltenindex_4 = intHelp
If Bereich(1, intHelp) = ParameterName_5 Then parameterSpaltenindex_5 = intHelp
If Bereich(1, intHelp) = SummeSpalte Then summeSpaltenindex = intHelp
Next
 Prüfung_1 = (ParameterName_1 = "" Or ParameterWert_1 = alle)
Prüfung_2 = (ParameterName_2 = "" Or ParameterWert_2 = alle)
Prüfung_3 = (ParameterName_3 = "" Or ParameterWert_3 = alle)
Prüfung_4 = (ParameterName_4 = "" Or ParameterWert_4 = alle)
Prüfung_5 = (ParameterName_5 = "" Or ParameterWert_5 = alle)
For intHelp = 2 To anzahlZeilen
If Bereich(intHelp, parameterSpaltenindex_1) = ParameterWert_1 OrPrüfung_1 Then
If Bereich(intHelp, parameterSpaltenindex_2) = ParameterWert_2 OrPrüfung_2 Then
If Bereich(intHelp, parameterSpaltenindex_3) = ParameterWert_3 Or Prüfung_3  _
Then
If Bereich(intHelp, parameterSpaltenindex_4) = ParameterWert_4 Or Prüfung_4  _
_
_
_
Then
If Bereich(intHelp, parameterSpaltenindex_5) = ParameterWert_5 Or Prü _
fung_5 Then
mySumme = mySumme + CSng(Bereich(intHelp, summeSpaltenindex))
End If
End If
End If
End If
End If
Next
mySummewenn = mySumme
End Function


Gruß Daniel
ps für die vielen Leerzeilen kann ich leider nichts, die werden vom Edior automatisch eingefügt

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige