22.07.2017, 13:07
(Dieser Beitrag wurde zuletzt bearbeitet: 29.07.2017, 18:53 von WillWissen.)
Ich habe eben eine kleine Performance-Messroutine geschrieben.
In dieser sind A:B durchgehende Zufallsdaten der Form A: [A-Z][A-Z][A-D] und B: [A-Z][A-Z] (also über 1048576 bzw. 65536 Zeilen).
Für D:E (entsprechend A:B) kann man in der Routine mit n eingeben, wie viele VERGLEICH-Formeln gerechnet werden sollen. n=30 bedeutet also 30 gleiche Formeln, die sich jeweils über knapp 2,1 Mio (=2^21) Daten her machen.
Verglichen werden {SUMME}, VERGLEICH, {VERGLEICH}, AGGREGAT, SUMMENPRODUKT und SUMMEWENNS.
1. Manchmal wird unterschieden, ob (A:A=D1)*(B:B=E1) oder (A:A&B:B=D1&E1) als Kriterium gerechnet wird. Überraschende Ergebnisse!
2. Bei VERGLEICH wird innen mit INDEX(A:A&B&B;) gerechnet. Auch hier eine Überraschung, die sich etwa hälftig auf den Effekt zu 1. sowie die Verwendung von INDEX statt {} aufteilt.
Ergebnisse:
1. AGGREGAT ist VERGLEICH soweit ebenbürtig (neopa hat recht)
2. {} scheint gegenüber ...INDEX(;)... im Vorteil zu sein (WF hat recht)
Es kommt aber erheblich auf den Einzelfall an. Auch kommt es ein wenig drauf an, ob das Arbeitsblatt frisch ist, oder das Makro schon mehrmals gelaufen ist (wie hier. Dann langsamer).
Anmerkung: Gibt es mehr als ein Auftreten, zeigen VERGLEICH und AGGREGAT das erste, VERWEIS das letzte und die Summenfunktionen deren Addition. Das muss dem Anwender klar sein.
Hier die Einzelergebnisse in Sekunden für n=30 und n=100 (Win10, xl2010, Surface Pro 4, Intel m3, 4 Kerne):
F: 023,87: =VERGLEICH(D1&E1;INDEX(A:A&B:B;);)
G: 006,82: {=VERGLEICH(D1&E1;A:A&B:B;)}
H: 020,00: =VERWEIS(2;1/(A:A&B:B=D1&E1);ZEILE(A:A))
I: 010,68: =SUMMENPRODUKT(ZEILE(A:A)*(A:A=D1)*(B:B=E1))
J: 011,14: =SUMMENPRODUKT(ZEILE(A:A);N(A:A=D1);N(B:B=E1))
K: 008,92: {=SUMME(ZEILE(A:A)*(A:A=D1)*(B:B=E1))}
L: 022,03: =AGGREGAT(15;6;ZEILE(A:A)/(A:A&B:B=D1&E1);1)
M: 011,16: =AGGREGAT(15;6;ZEILE(A:A)/(A:A=D1)/(B:B=E1);1)
N: 003,55: =SUMMEWENNS(C:C;A:A;D1;B:B;E1)
O: 012,55: =SUMMENPRODUKT(C:C;N(A:A=D1);N(B:B=E1))
P: 025,09: =SUMMENPRODUKT(C:C;N(A:A&B:B=D1&E1))
Q: 010,84: =SUMMENPRODUKT(C:C;-(A:A=D1);-(B:B=E1))
R: 011,01: =SUMMENPRODUKT(C:C;--(A:A=D1);--(B:B=E1))
S: 011,75: =SUMMENPRODUKT(C:C;1*(A:A=D1);1*(B:B=E1))
T: 012,00: =SUMMENPRODUKT(C:C;0+(A:A=D1);0+(B:B=E1))
U: 010,99: =VERWEIS(2;1/(A:A=D1)/(B:B=E1);ZEILE(A:A))
F: 069,23: =VERGLEICH(D1&E1;INDEX(A:A&B:B;);)
G: 017,79: {=VERGLEICH(D1&E1;A:A&B:B;)}
H: 065,76: =VERWEIS(2;1/(A:A&B:B=D1&E1);ZEILE(A:A))
I: 033,02: =SUMMENPRODUKT(ZEILE(A:A)*(A:A=D1)*(B:B=E1))
J: 035,79: =SUMMENPRODUKT(ZEILE(A:A);N(A:A=D1);N(B:B=E1))
K: 027,73: {=SUMME(ZEILE(A:A)*(A:A=D1)*(B:B=E1))}
L: 073,49: =AGGREGAT(15;6;ZEILE(A:A)/(A:A&B:B=D1&E1);1)
M: 035,02: =AGGREGAT(15;6;ZEILE(A:A)/(A:A=D1)/(B:B=E1);1)
N: 011,36: =SUMMEWENNS(C:C;A:A;D1;B:B;E1)
O: 038,11: =SUMMENPRODUKT(C:C;N(A:A=D1);N(B:B=E1))
P: 077,49: =SUMMENPRODUKT(C:C;N(A:A&B:B=D1&E1))
Q: 034,25: =SUMMENPRODUKT(C:C;-(A:A=D1);-(B:B=E1))
R: 034,03: =SUMMENPRODUKT(C:C;--(A:A=D1);--(B:B=E1))
S: 036,75: =SUMMENPRODUKT(C:C;1*(A:A=D1);1*(B:B=E1))
T: 036,54: =SUMMENPRODUKT(C:C;0+(A:A=D1);0+(B:B=E1))
U: 034,75: =VERWEIS(2;1/(A:A=D1)/(B:B=E1);ZEILE(A:A))
Hier noch der Code (mit n = 5, damit es beim Erstdurchlauf nicht zu lange dauert):
In dieser sind A:B durchgehende Zufallsdaten der Form A: [A-Z][A-Z][A-D] und B: [A-Z][A-Z] (also über 1048576 bzw. 65536 Zeilen).
Für D:E (entsprechend A:B) kann man in der Routine mit n eingeben, wie viele VERGLEICH-Formeln gerechnet werden sollen. n=30 bedeutet also 30 gleiche Formeln, die sich jeweils über knapp 2,1 Mio (=2^21) Daten her machen.
Verglichen werden {SUMME}, VERGLEICH, {VERGLEICH}, AGGREGAT, SUMMENPRODUKT und SUMMEWENNS.
1. Manchmal wird unterschieden, ob (A:A=D1)*(B:B=E1) oder (A:A&B:B=D1&E1) als Kriterium gerechnet wird. Überraschende Ergebnisse!
2. Bei VERGLEICH wird innen mit INDEX(A:A&B&B;) gerechnet. Auch hier eine Überraschung, die sich etwa hälftig auf den Effekt zu 1. sowie die Verwendung von INDEX statt {} aufteilt.
Ergebnisse:
1. AGGREGAT ist VERGLEICH soweit ebenbürtig (neopa hat recht)
2. {} scheint gegenüber ...INDEX(;)... im Vorteil zu sein (WF hat recht)
Es kommt aber erheblich auf den Einzelfall an. Auch kommt es ein wenig drauf an, ob das Arbeitsblatt frisch ist, oder das Makro schon mehrmals gelaufen ist (wie hier. Dann langsamer).
Anmerkung: Gibt es mehr als ein Auftreten, zeigen VERGLEICH und AGGREGAT das erste, VERWEIS das letzte und die Summenfunktionen deren Addition. Das muss dem Anwender klar sein.
Hier die Einzelergebnisse in Sekunden für n=30 und n=100 (Win10, xl2010, Surface Pro 4, Intel m3, 4 Kerne):
F: 023,87: =VERGLEICH(D1&E1;INDEX(A:A&B:B;);)
G: 006,82: {=VERGLEICH(D1&E1;A:A&B:B;)}
H: 020,00: =VERWEIS(2;1/(A:A&B:B=D1&E1);ZEILE(A:A))
I: 010,68: =SUMMENPRODUKT(ZEILE(A:A)*(A:A=D1)*(B:B=E1))
J: 011,14: =SUMMENPRODUKT(ZEILE(A:A);N(A:A=D1);N(B:B=E1))
K: 008,92: {=SUMME(ZEILE(A:A)*(A:A=D1)*(B:B=E1))}
L: 022,03: =AGGREGAT(15;6;ZEILE(A:A)/(A:A&B:B=D1&E1);1)
M: 011,16: =AGGREGAT(15;6;ZEILE(A:A)/(A:A=D1)/(B:B=E1);1)
N: 003,55: =SUMMEWENNS(C:C;A:A;D1;B:B;E1)
O: 012,55: =SUMMENPRODUKT(C:C;N(A:A=D1);N(B:B=E1))
P: 025,09: =SUMMENPRODUKT(C:C;N(A:A&B:B=D1&E1))
Q: 010,84: =SUMMENPRODUKT(C:C;-(A:A=D1);-(B:B=E1))
R: 011,01: =SUMMENPRODUKT(C:C;--(A:A=D1);--(B:B=E1))
S: 011,75: =SUMMENPRODUKT(C:C;1*(A:A=D1);1*(B:B=E1))
T: 012,00: =SUMMENPRODUKT(C:C;0+(A:A=D1);0+(B:B=E1))
U: 010,99: =VERWEIS(2;1/(A:A=D1)/(B:B=E1);ZEILE(A:A))
F: 069,23: =VERGLEICH(D1&E1;INDEX(A:A&B:B;);)
G: 017,79: {=VERGLEICH(D1&E1;A:A&B:B;)}
H: 065,76: =VERWEIS(2;1/(A:A&B:B=D1&E1);ZEILE(A:A))
I: 033,02: =SUMMENPRODUKT(ZEILE(A:A)*(A:A=D1)*(B:B=E1))
J: 035,79: =SUMMENPRODUKT(ZEILE(A:A);N(A:A=D1);N(B:B=E1))
K: 027,73: {=SUMME(ZEILE(A:A)*(A:A=D1)*(B:B=E1))}
L: 073,49: =AGGREGAT(15;6;ZEILE(A:A)/(A:A&B:B=D1&E1);1)
M: 035,02: =AGGREGAT(15;6;ZEILE(A:A)/(A:A=D1)/(B:B=E1);1)
N: 011,36: =SUMMEWENNS(C:C;A:A;D1;B:B;E1)
O: 038,11: =SUMMENPRODUKT(C:C;N(A:A=D1);N(B:B=E1))
P: 077,49: =SUMMENPRODUKT(C:C;N(A:A&B:B=D1&E1))
Q: 034,25: =SUMMENPRODUKT(C:C;-(A:A=D1);-(B:B=E1))
R: 034,03: =SUMMENPRODUKT(C:C;--(A:A=D1);--(B:B=E1))
S: 036,75: =SUMMENPRODUKT(C:C;1*(A:A=D1);1*(B:B=E1))
T: 036,54: =SUMMENPRODUKT(C:C;0+(A:A=D1);0+(B:B=E1))
U: 034,75: =VERWEIS(2;1/(A:A=D1)/(B:B=E1);ZEILE(A:A))
Hier noch der Code (mit n = 5, damit es beim Erstdurchlauf nicht zu lange dauert):
Code:
Sub TimerOfLookups()
[1:1].RowHeight = 13: n = 5: Cells.Clear: Range("F1:U" & n) = "not done yet": [C1] = "1": [C:C].DataSeries
Range("A:A,D1:D" & n).FormulaR1C1 = "=CHAR(RAND()*26+65)&CHAR(RAND()*26+65)&CHAR(RAND()*4+65)"
[A:A] = [A:A].Value: Range("D1:D" & n) = Range("D1:D" & n).Value
Range("B:B,E1:E" & n).FormulaR1C1 = "=CHAR(RAND()*26+65)&CHAR(RAND()*26+65)"
[B:B] = [B:B].Value: Range("E1:E" & n) = Range("E1:E" & n).Value
Call Kalk("F", n, False, "=MATCH(RC[-2]&RC[-1],INDEX(C[-5]&C[-4],),)")
Call Kalk("G", n, True, "=MATCH(RC[-3]&RC[-2],C[-6]&C[-5],)")
Call Kalk("H", n, False, "=LOOKUP(2,1/(C[-7]&C[-6]=RC[-4]&RC[-3]),ROW(C[-7]))")
Call Kalk("I", n, False, "=SUMPRODUCT(ROW(C[-8])*(C[-8]=RC[-5])*(C[-7]=RC[-4]))")
Call Kalk("J", n, False, "=SUMPRODUCT(ROW(C[-9]),N(C[-9]=RC[-6]),N(C[-8]=RC[-5]))")
Call Kalk("K", n, True, "=SUM(ROW(C[-10])*(C[-10]=RC[-7])*(C[-9]=RC[-6]))")
Call Kalk("L", n, False, "=AGGREGATE(15,6,ROW(C[-11])/(C[-11]&C[-10]=RC[-8]&RC[-7]),1)")
Call Kalk("M", n, False, "=AGGREGATE(15,6,ROW(C[-12])/(C[-12]=RC[-9])/(C[-11]=RC[-8]),1)")
Call Kalk("N", n, False, "=SUMIFS(C[-11],C[-13],RC[-10],C[-12],RC[-9])")
Call Kalk("O", n, False, "=SUMPRODUCT(C[-12],N(C[-14]=RC[-11]),N(C[-13]=RC[-10]))")
Call Kalk("P", n, False, "=SUMPRODUCT(C[-13],N(C[-15]&C[-14]=RC[-12]&RC[-11]))")
Call Kalk("Q", n, False, "=SUMPRODUCT(C[-14],-(C[-16]=RC[-13]),-(C[-15]=RC[-12]))")
Call Kalk("R", n, False, "=SUMPRODUCT(C[-15],--(C[-17]=RC[-14]),--(C[-16]=RC[-13]))")
Call Kalk("S", n, False, "=SUMPRODUCT(C[-16],1*(C[-18]=RC[-15]),1*(C[-17]=RC[-14]))")
Call Kalk("T", n, False, "=SUMPRODUCT(C[-17],0+(C[-19]=RC[-16]),0+(C[-18]=RC[-15]))")
Call Kalk("U", n, False, "=LOOKUP(2,1/(C[-20]=RC[-17])/(C[-19]=RC[-16]),ROW(C[-20]))")
MsgBox [DA1]
End Sub
Sub Kalk(Spalte, n, Arr As Boolean, Formel): a = Timer
If Arr Then
Range(Spalte & "1").FormulaArray = Formel: Range(Spalte & "1:" & Spalte & n).FillDown
Else
Range(Spalte & "1:" & Spalte & n).FormulaR1C1 = Formel
End If: b = Timer - a
Formel = Range(Spalte & "1").FormulaLocal
Range(Spalte & "1:" & Spalte & n) = Range(Spalte & "1:" & Spalte & n).Value
Range("A" & Spalte & "1") = b
Range("B" & Spalte & "1").FormulaR1C1 = "=TEXT(RC[-26],""000,00"")"
Range("C" & Spalte & "1") = IIf(Arr, "{", " ") & Formel & IIf(Arr, "}", " ")
[DA1] = [DA1] & Chr(10) & Spalte & ": " & Range("B" & Spalte & "1") & ": " & Range("C" & Spalte & "1")
End Sub