In diesem Beitrag geht es um ein spezielleres Thema in Power Apps - den Vergleich zweier Aggregatfunktionen -, nichtsdestotrotz möchten wir unser Wissen, vor allem vor dem Hintergrund, dass wir nach Recherche mit besten Wissen und Gewissen weder in der Microsoft Power Apps Dokumentation noch in den zahlreichen Blogs und der umfassenden Power Apps Community hierzu Beiträge gefunden haben, mit Euch teilen.
Worum geht es?
Wir wollen die Power Apps Funktionen CountIf und CountRows kurz gegenüberstellen und auf eine Auffälligkeit hinsichtlich der App Performance eingehen, die wir bei der Entwicklung einer Kundenanwendung festgestellt haben.
Use Case: Power App zur Lagerverwaltung
Um ganz kurz den Rahmen dafür zu geben, wo diese Punkte aufgefallen sind:
Bei der Power App handelt es sich um eine Lösung, die der Kunde zur Verwaltung seines Lagers nutzt. Neben der Bewirtschaftung der Artikel durch die internen Kollegen (Lagermeister, Disposition usw.) war vor allem wichtig, dass die Monteure im Feld/Außendienst eine schnelle und besonders einfach Möglichkeit erhalten auf dem Tablet bzw. anderen mobilen Endgeräten wichtige Informationen zu einem Lagerartikel wie Artikelnummer, Lieferant, Einkauf- oder Verkaufspreis sowie die Materialbestände einzusehen.
Eine Funktion innerhalb dieser Power App ist es, dass sich die Monteure eine Art "digitalen Packzettel" für ihre Bauvorhaben erstellen können. Wie wir es vom Shopping auf Amazon also gewöhnt sind, klickt der Monteur sich innerhalb der Power App durch die einzelnen Lagerkategorien und kann Artikel in seinen "Warenkorb" packen.
Eine wichtige Information bei so einem Warenkorb ist zu sehen, wie viele Artikel einer bestimmten Artikelnummer oder Artikelbezeichnung ich in meinem Warenkorb habe.
Count-Funktionen in Power Apps
Hierfür haben wir bis dato die Aggregatfunktion CountRows() von Power Apps verwendet. Zudem gibt es Stand März 2021 noch die Funktionen Count, CountA und CountIf in PowerApps, die "alle Datensätze in einer Tabelle oder alle Datensätze, die eine Bedingung erfüllen [zählen]" (Microsoft, 2015)
Wir konzentrieren uns in diesem Beitrag auf CountRows() und CountIf().
Delegation von Count-Funktionen
Bevor wir uns die Funktionen weiter im Detail anschauen, soll an dieser Stelle kurz erwähnt werden, dass laut Dokumentation von Microsoft Stand März 2021 keine dieser Funktionen delegierbar ist. Wir könnten nun an dieser Stelle einen Roman über Delegation in Power Apps schreiben, aber verweisen dafür lieber auf die Dokumentation und um es einfach zu halten:
Verwendet ihr eine dieser Funktionen in einer Datenquelle mit mehr als 2000 Zeilen, so wird Euch die Power App nur die ersten 2000 Zeilen ausgeben. Es ist also unglaublich wichtig, dieses Konzept zu verstehen und Datenmengen entsprechend zu organisieren in Eurer Power Apps. Bestenfalls immer in Sammlungen unter dieser Grenze von 2000 Zeilen. Standardmäßig liegt dieser Wert beim Erstellen von Power Apps sogar nur auf 500, ihr könnt diesen aber in den Einstellungen der Power App manuell auf 2000 erhöhen.
Zudem erhaltet Ihr beim verwenden der Funktion auch eine Delegationswarnung:
Aufbau von CountRows() und CountIf()
Nachdem wir nun unsere Tränen getrocknet haben, dass die Funktionen nur bei den ersten 2000 Zeilen funktionieren, wollen wir uns diese dennoch im Detail anschauen:
CountRows ist wie folgt aufgebaut:
//Zählt alle Datensätze in der Tabelle -> z.B. Collection oder SharePoint Liste
CountRows(Tabelle)
CountIf wie folgt:
//Zählt alle Datensätze, die eine bestimmte Bedingung erfüllen in der Datenquelle
CountIf(Tabelle; Bedingung)
Artikel zählen, die die gleiche Artikelbezeichnung haben
In der Praxis sieht das dann ungefähr so aus:
Beide Abfragen unterhalb zählen die Anzahl der Artikel, die dieselbe Artikelbezeichnung haben.
Mit CountRows filtern wir unsere Collection colEinkaufswagen nach den Artikeln, die der Artikelbezeichnung entsprechen, die sich aktuell in der Galerie befindet
HIER GALERIE FOTO
CountRows(
Filter(
colEinkaufswagen;
ThisItem.Artikelbezeichnung = Artikelbezeichnung
)
)
Mit CountIf zählen wir nur die Artikel, die das Kriterium erfüllen.
Die Bezeichnung von colEinkaufswagen als "InnerTable" verwenden wir hier nur zum besseren Referenzieren, müsste aber nicht sein.
CountIf(
colEinkaufswagen As InnerTable;
ThisItem.Artikelbezeichnung = InnerTable.Artikelbezeichnung
)
Beide Abfragen bringen 1:1 dasselbe Ergebnis: Sie zählen alle Artikel, die sich im Warenkorb befinden und in ihrer Artikelbezeichnung übereinstimmen.
Was ist nun besser an CountIf()?
Die Schönheit des Codes Das mag vielleicht eine subjektive Meinung sein aber unserer Ansicht nach ist der Code mit CountIf() verständlicher und trennt auch sauber die Datenquelle und die zu erfüllende Bedingung (Artikelbezeichnung = Aktuelle Artikelbezeichnung)
Die Performance Viel wichtiger als unsere subjektive Empfindung ist die Messung der Performance, bei der CountIf() in allen Fällen besser weggekommen ist.
Dafür haben wir beide Varianten in mehrfachen Durchläufen gegeneinander laufen lassen
Der Code für CountIf() sah wie folgt aus:
//Startzeit erfassen
Set(varStart_CountIf; Now());;
//Anzahl der Zeilen mit CountRows und Filter zählen
Set(varRows_CountIf; CountIf(CL_Lagerliste; MIN = 2));;
//Dauer der Abfrage erfassen in Millisekunden
Set(varDuration_CountIf; DateDiff(varStart_CountIf; Now(); Milliseconds))
Der Code für CountRows sah wie folgt aus:
//Startzeit erfassen
Set(varStart_CountRows; Now());;
//Anzahl der Zeilen mit CountIf und Bedingungen innerhalb zählen
Set(varRows_CountRows; CountRows(Filter(CL_Lagerliste; MIN = 2)));;
//Dauer der Abfrage erfassen in Millisekunden
Set(varDuration_CountRows; DateDiff(varStart_CountRows; Now(); Milliseconds))
Im Ergebnis benötigte unsere Abfrage mit CountIf() zwischen 5 und 15 Millisekunden, während CountRows() meist 1000 bis 1500 (1-1,5 Sekunden) oder mehr gebraucht hat, um diese Abfrage auszuführen.
Bei der Datenquelle handelt es sich um ca. 1800 Datensätze, also ein relativ kleines Dataset. Mehr als 2000 würde letztendlich aufgrund der erwähnten Delegationsproblematik mit diesen Formeln ohnehin nicht funktionieren. Nichtsdestotrotz ist das ein merklicher Unterschied, der gerade zum tragen kommt, wenn diese Abfrage in einer Galerie für jede Zeile ausgeführt werden sollte. Aus diesem Grund solltet Ihr auch darauf achten, wenn ihr solche Berechnungen innerhab einer Gallerie durchführt, die Items der Gallerie aus einer Collection zu beziehen, die ihr vorher aus der Datenquelle generiert habt. In unserem Fall generieren wir für den Warenkorb die Collection "colEinkaufswagen". Durch die lokale Datenverarbeitung bleibt die App auch mit CountIf() (oder sogar mit CountRows()) performant.
Warum dauert es mit CountRows() länger?
Da wir uns nicht als Power Apps Gurus bezeichnen würden, können wir hier nur Vermutungen aufstellen.
Wir denken es hängt damit zusammen, dass bei einer Filter()-Funktion Power Apps die gesamte Datenquelle nach den Datensätzen "durchkämmen" muss, die das Kriterium erfüllen, während dies scheinbar in optimalerer Weise mit CountIf() ausgeführt wird. Möglicherweise werden Datensätze, die das Kriterium nicht erfüllen von vornherein ausgeschlossen.
Wie auch immer: CountIf gewinnt für uns das Rennen, da uns vor allem mobile Performance bei dieser Anwendung sehr wichtig ist.
Wenn Euch der Beitrag gefallen habt, abonniert gerne unseren Blog.
Wenn Ihr eine kleine Lager App braucht oder mit anderen Themen im Bereich Microsoft 385 / Power Platform durchstarten wollt, nehmt einfach direkt Kontakt zu uns auf.
Hi, ich hätte Interesse an dieser kleiner Lager App, ich versuche für unser Team eine kleine App zu bauen um Material aus einer vorgegebenen Liste in einen Warenkork zu packen und diesen dann beim bestellen (Checkout) am liebsten per PDF direkt per Mail an eine vorher ausgewählte Adresse zu verschicken. Leider habe ich noch so viele Baustellen in der App das ich hier nicht weiter komme. Ich wäre über eine Hilfe oder deine App als Vorlage echt dankbar.
Mit freundlichen Grüßen
Christian