Performance-optimized access to Vertec objects

What you should pay attention to when customizing to ensure long-term good performance.

Product line

Standard

|

Expert

Operating mode

CLOUD ABO

|

ON-PREMISES

Modules

Services & CRM

Budget & Phases

Purchases

Resource Planning

Business Intelligence

Created: 14.07.2023
Updated: 07.12.2023 | Description fixed: vtcapp.fetchlinkmembers() has no return value.

Abgesehen von der Performance im Netz und beim Vertec Customizing ist es zentral, dass auch bei Ordner-Expressions und in Listeneinstellungen - also immer dann, wenn Vertec Daten via OCL  abgefragt werden - die Performance im Blick gehalten wird.

Expressions und Vorgänge, die am Anfang und mit kleinen Datenmengen problemlos laufen, können zu Performancefressern werden, je mehr Daten im System vorhanden sind.

Es lohnt sich, die Zugriffe von Anfang an performant zu designen und die in diesem Artikel beschriebenen Dos und Don'ts zu verstehen und zu beachten.

Und auch Punkt 6 von unserem 10-Punkte-Plan für eine zukunftsfähige Vertec-Installation zu beachten: Low Code Customizing vs. Overengineering .

Grundsätzliches

Vertec lädt die Objekte, auf die es zugreifen muss, von der Datenbank ins Session Memory. Sind sie einmal im Memory, ist der Zugriff darauf schnell. Sobald dann aber auf Linkobjekte, Sublisten etc. dieser Objekte zugegriffen wird, müssen neue Objekte von der Datenbank geladen werden.

Je weniger (und je weniger häufig) Objekte von der Datenbank ins Memory geladen werden müssen, desto performanter der Vorgang. Dies muss im Hinterkopf gehalten werden, wenn Listen gefiltert werden sollen: Viele Objekte zu laden, wenn davon nur eine Handvoll gebraucht werden, kann oft vermieden werden. Oder es können Objekte in einem Rutsch ins Memory vorgeladen werden, dann ist der Einzelzugriff schneller.

Es ist wichtig, dass man die Expression und was sie macht, versteht, um performante Entscheidungen treffen zu können.

Und ist eine performantere Lösung einmal nicht möglich, sollte man die Gründe dafür kennen und auch verstehen, warum eine Liste oder Auswertung lange dauert (und sie im Namen entsprechend kennzeichnen, in einer separaten Ordnerstruktur ablegen, über Nacht laufen lassen , etc.).

Wie funktioniert der Zugriff via OCL

OCL wertet Expressions streng von links nach rechts aus und verwendet das Resultat der ersten Teilexpression dann als Quelle für die nächste Teilexpression.

Einfache Expression wie projekt (bzw. Projekt.allInstances) machen im Normalfall keine Performance Probleme. Erweitert man diese Expression um ein persistentes Member, z.B. "aktiv" (projekt->select(aktiv)), so dauert das genau gleich lang, denn die Projekte sind mit allen Members schon geladen.

Selektiert man nun aber auf eine Subliste wie zum Beispiel projekt->select(phasen->size>0), also alle Projekte, die mindestens eine Phase haben, wird es plötzlich viel langsamer. Das ist so, weil die Berechnung wie oben beschrieben von links nach rechts abgearbeitet wird:

  1. Alle Projekte reinladen.
  2. Dann für jedes Projekt die Expression phasen->size>0 auswerten. Das bedeutet, dass für jedes einzelne Projekt in der Liste die Phasen dieses Projektes einzeln von der Datenbank geladen werden und dann entschieden wird, ob es in die Liste kommt oder nicht.
  3. Dann beim nächsten Projekt das gleiche, bis zum Ende der Liste.

Vertec versucht die Daten optimiert zu laden bei solchen (einfachen) Expressions. Wenn wie im obigen Beispiel klar ist, dass alle Phasen der Projekte in der Liste benötigt werden, wird bei der Durchführung dieser Expression die gesamte Phasenliste auf einmal ins Memory geladen. Es erfolgt also nur ein einmaliger Datenbankzugriff. Bei komplexen Expressions oder falls Sublisten von Sublisten geladen werden müssen, ist dies jedoch automatisiert nicht möglich und es muss selbst darauf geachtet werden.

Wie funktioniert der Zugriff via SQL

Bei Abfragen via SQL (SQL-Ordner, vtcapp.getwithsql(), Leistungssummen) werden die Filter auf dem Datenbank Server angewendet und nur die resultierenden Objekte ins Memory geladen.

Simple Anfragen wie "alle Objekte einer bestimmten Klasse" sind deshalb gleich schnell wie bei OCL, sobald aber gefiltert wird, kann SQL schneller sein, weil die Filterung auf dem Datenbank Server zusätzlich optimiert ist und nicht alle Objekte geladen werden müssen.

Sind die Objekte schon geladen bzw. vorgeladen , lohnt sich die Verwendung von OCL statt SQL, da dann nur noch auf das Memory, nicht mehr auf die Datenbank zugegriffen werden muss.

Zugriffsorte

Der Zugriff auf grössere Mengen von Vertec Daten erfolgt an diesen Orten:

  • In Office-Berichten : Diese greifen via Python-Code auf die Daten zu, und man hat somit alle Möglichkeiten für einen performanten Zugriff.
  • In Vertec-Listen : Hier kann angesetzt werden beim Laden der Daten, mit der Wahl des Ordertyps sowie den Filter-Expressions.
  • In Spaltenexpressions : Sobald Berechnungen gemacht und Sublisten (und Zusatzfelder) angezeigt werden, muss auf die Performance geachtet werden. Hier bietet sich der Einsatz von List Controllern und Custom Renderern an.
  • In Scripts : Auch hier hat man wie bei den Office-Berichten alle Möglichkeiten für einen performanten Zugriff.

Vertec-Listen

Bei Listen gilt: Je länger eine Liste (potenziell) ist, desto mehr muss man aufpassen, wie man sie aufbaut bzw. welche Spaltenexpressions man darin verwendet.

Vertec Listen sind beim Laden optimiert. Nur die sichtbaren Zellen (plus eine weitere "Seite") werden berechnet. Scrollt man über diesen Bereich hinaus, werden die benötigten weiteren Objekte geladen usw.

Deshalb kann das Umsortieren oder der Export nach Excel plötzlich sehr viel länger dauern als die Anzeige der Liste selbst, weil in diesem Fall alle Objekte geladen werden müssen.

Auch wenn Spalten summiert werden, ist es so, dass alle Objekte geladen werden müssen, damit die Summe gebildet werden kann.

SQL-Ordner

SQL-Ordner sind empfehlenswert, wenn aus einer grossen Datenmenge bestimmte Objekte aufgrund einer Bedingung selektiert werden sollen. Im Unterschied zum Expression-Ordner erfolgt die Selektion der Daten durch den Datenbankserver, was in den meisten Fällen schneller ist.

Der Nachteil von SQL-Ordnern ist, dass sie nicht automatisch auf Änderungen von Daten reagieren und dass die Flexibilität von OCL für die Abfragen nicht zur Verfügung steht.

Expression-Ordner

Der Vorteil von Expression-Ordnern ist, dass die Daten "live" sind, das heisst, sich automatisch aktualisieren, wenn sich an den Daten etwas ändert.

Der Nachteil ist, dass die Daten nicht wie beim SQL-Ordner durch den Datenbankserver selektiert werden, sondern alle Daten reingeladen und erst dann selektiert werden.

Ordner

Bei den Ordnern sind die Objekte den Ordnern direkt zugeordnet und werden ungefiltert angezeigt, somit ist das Laden der Objekte normalerweise nicht performancerelevant.

Bei diesem Ordnertyp muss vor allem auf die Spaltenexpressions geachtet werden, denn diese können sehr wohl viele weitere Daten laden und den Ordner verlangsamen.

Vorsicht bei Inclusive/Exclusive Bedingungen in Stichwort-Ordnern: Diese Bedingungen sind performancerelevant, weil die Daten geprüft werden müssen. Insbesondere Inclusive sollte mit Bedacht verwendet werden, da dabei ALLE entsprechenden Daten im System geprüft werden müssen, was sehr lange dauern kann.

Link-Container

Link-Container sind die "Unterordner", die über einen Custom-Link-Typ oder einen Wrapper-Link-Typ zustande kommen. Sobald Objekte verlinkt werden, erscheinen sie in diesen Listen.

Hier empfehlen sich folgende Grundsätze:

  • Nur Link-Container anzeigen, die nötig sind, also über die Benutzeroberfläche erreicht werden sollen. In diesem Fall nicht nur Container anzeigen , sondern auch Container immer anzeigen wählen - dann muss er für die Anzeige nicht prüfen, ob es bereits Links hat, was schneller ist.
  • Bei Wrapper-Link-Typen auf performante Expressions achten.

Spaltenexpressions

Egal, in welchem der hier genannten Ordnertypen oder Link-Containern sich die Daten befinden und wie performant sie geladen werden - meist sind es die nicht performanten Spaltenexpressions, die eine Liste in die Knie zwingen.

Werden nur persistente Attribute (also Felder auf dem Objekt selbst) angezeigt, verlangsamt sich die Liste nach dem Laden nicht mehr, weil die Werte zusammen mit den Objekten bereits geladen sind.

Sobald aber auf Sublisten oder andere Objekte zugegriffen oder Berechnungen angestellt werden, muss auf die Performance geachtet werden. Die Expressions in den Spalten werden Zeile für Zeile abgearbeitet und laden je nachdem viele verschiedene Objekte. Sehr einfache Expressions versucht Vertec optimiert zu laden (siehe oben), aber oft ist das nicht automatisch möglich.

Deshalb liegt bei den Spaltenexpressions ein grosses Optimierungspotenzial für performante Listen. Oft lohnt sich der Einsatz eines List Controllers für die Bereitstellung der Daten.

Haben Sie eine Liste, die bereits langsam ist, können Sie mit dem Script: Ordnerperformance testen herausfinden, welche Spalte(n) Sie optimieren sollten.

List Controller

Bei allen hier genannten Ordnertypen und Link-Containern kann mit List Controllern gearbeitet werden, um Objekte vorzuladen oder Berechnungen zu machen.

Der List Controller hat dabei keinen Einfluss auf die geladenen Daten, er bestimmt also nicht die Liste, die angezeigt wird, und kann dabei performancemässig auch keine Verbesserung erreichen. Er dient der Performance in den Spalten und kann zwei Aufgaben übernehmen:

  • Preloading : Alle Daten in einem Rutsch ins lokale Memory laden, damit der Zugriff in der Liste schneller ist.
  • Daten berechnen und filtern, auf die dann in den Spalten via Custom Renderer zugegriffen werden kann.

Basis ist eine Datenbank mit 10'000 Projekten und 42'000 Projektphasen. Die Projektliste ist dabei die Standardprojektliste.

1. Test: Selektieren nach Attributen auf dem Objekt selbst (persistente Members)

Art des Ordners Expression Laufzeit Bemerkung
OCL projekt 11s Das reine Laden von Objekten stellt in der Regel kein Performanceproblem dar.
OCL projekt->select(code='C12345') 9s

Ist schneller als obige Expression, weil die Liste nur ein Projekt darstellen muss statt 10'000, obwohl alle reingeladen werden müssen.

OCL projekt->select(aktiv) 10s Dito
SQL code='C12345' 0.5s  

Hier sieht man gut: ->select auf ein persistentes Attribut ist performancemässig kein Problem. SQL ist bei langen Listen schneller, wenn nur wenig Objekte selektiert werden.

2. Test: Selektieren nach Zusatzfeld

Art des Ordners Expression Laufzeit Bemerkung
OCL projekt->select(zusatzfeldbool('auswahl')) 7m 31s! Das Filtern nach Zusatzfeldern ist extrem ineffizient, wenn die Zusatzfelder noch nicht reingeladen sind, weil
sie einzeln für jedes Projekt reingeladen werden müssen.
OCL zusatzfeldklasse->select(boldid=1234567).zusatzfeldInstances
->select(wertBoolean).usereintrag->oclAsType(Projekt)
2.5s!

Gleiche Liste wie oben, ausgehend vom Zusatzfeld statt vom Projekt. 180x schneller!

Die Expression ist sogar noch schneller als der ->select nach dem aktiv Feld (siehe oben), weil nur die betroffenen Projekte dann wirklich reingeladen werden müssen.

SQL bold_id IN (SELECT usereintrag FROM zusatzfeld WHERE metazusatzfeld=1234567 AND wertboolean=1) 1s Das SQL ist klar schneller, dafür ist die Liste dann aber nicht subscribed, d.h. sie aktualisiert sich nicht automatisch bei Änderungen.

3. Test: Selektieren nach einer Subliste

Hier werden die Projekte nach der Eigenschaft aktiv auf den Phasen selektiert.

Art des Ordners Expression Laufzeit Bemerkung
OCL projekt->select(phasen->select(aktiv)->size>0) 2m 22s Sehr ineffizient, weil die Phasen für jedes Projekt einzeln reingeladen werden müssen. Von den 10'000 Projekten werden ca. 2'000 selektiert
OCL projektphase->select(aktiv).projekt 1m 35s

Hier müssen die Projekte einzeln reingeladen werden von den Phasen aus. Es geht aber hier um 2'000 Projekte anstatt 42'000 Phasen auf 10'000 Projekten (also um 2'000 einzelne Zugriffe statt um 10'000).

Bei beiden Varianten werden alle Phasen des Systems reingeladen.

SQL bold_id IN (SELECT projekt FROM projektphase WHERE aktiv=1) 3s Das SQL ist klar schneller, dafür ist die Liste dann aber nicht subscribed, d.h. sie aktualisiert sich nicht automatisch bei Änderungen.

Erkenntnis: Das Selektieren einer langen Objektliste auf Eigenschaften einer "Subliste" ist extrem teuer und sollte in OCL vermieden werden. Auch Zusatzfelder sind solche "Sublisten".

Alternativ von der Subliste ausgehen oder (bei Zusatzfeldern) die zu selektierende Information in ein persistentes Member des Objektes schreiben (via Keys oder Tags ).

Preloading

In Scripts, Office-Reports und bei komplexen Spaltenexpressions in Vertec-Listen lohnt es sich, die benötigten Sublisten in einem Rutsch ins Memory zu laden. Bei der Verarbeitung muss das System dann nicht jedes Mal auf die Datenbank zugreifen, sondern kann die Objekte direkt im Memory ansprechen, was viel schneller ist.

Das kann via Preloading der Objekte in einem List Controller geschehen und gilt natürlich auch für alle anderen Scripts, wo Daten geladen werden, z.B. in Office-Berichten .

Für das Preloading gibt es folgende Varianten:

vtcapp.getwithsql()

Die Methode vtcapp.getwithsql() erlaubt das Laden von Objekten via SQL. Die Filterkriterien werden dabei auf dem Server ausgeführt und nur die resultierenden Objekte geladen.

Der ausführende Benutzer muss über Administratorenrechte oder über das SQL Query Recht verfügen. Für die Erteilung von temporären Administratorenrechte steht die Variante der erweiterten Berechtigungen zur Verfügung.

 # Preload der offenen Leistungen in Periode von einer Liste von Bearbeitern
bearbIdList = bearblist.idstring()    
whereclause = vtcapp.sqlwherebetweendate('datum', dateFrom, dateTo)
    
with vtcapp.SystemContext():
    leistList = vtcapp.getwithsql("OffeneLeistung", "bearbeiter IN ({}) AND {}".format(bearbIdList, whereclause), "")

vtcapp.fetchlinkmembers()

Die Methode vtcapp.fetchlinkmembers() lädt für eine Liste von Objekten die Subliste rein, also die Zielobjekte, und macht den Multilink gleichzeitig current (was heisst, dass beim Zugriff auf den Link die Liste nicht nochmal geladen wird). Deshalb sollte das fetchlinkmembers() unmittelbar vor der Weiterverarbeitung erfolgen.

# Loop durch die Phasen von Projekten, welche mindestens eine Phase "erteilt" haben
projekte = vtcapp.getwithsql("Projekt", "bold_id IN (SELECT projekt FROM projektphase WHERE status=1)", "")
vtcapp.fetchlinkmembers(projekte, "phasen")
for projekt in projekte:
    x = projekt.evalocl("phasen->select(status=1)")

Diese Methode birgt riesiges Optimierungspotenzial, siehe nachfolgende Beispiele:

Ausgangslage: In einer grossen Datenbank mit Zehntausenden von Projekten und Phasen soll durch die Phasen derjenigen Projekten geloopt werden, welche mindestens eine Phase "erteilt" haben.

Original: naiv via OCL
projekte = vtcapp.evalocl("projekt->select(phasen->select(status=1)->size>0)")
for projekt in projekte:
    x = projekt.evalocl("phasen->select(status=1)")

Dauer: 37s. Die Umgebung ist hier sehr performant, die Dauer könnte noch viel höher sein bei weniger performanter Umgebung.

Optimierung 1: Die Projekte werden via SQL preloaded
projekte = vtcapp.getwithsql("Projekt", "bold_id IN (SELECT projekt FROM projektphase WHERE status=1)", "")
for projekt in projekte:
    x = projekt.evalocl("phasen->select(status=1)")

Dauer: 21s, eine Verbesserung um 43%. Es müssen viel weniger Objekte reingeladen werden (nur die relevanten Projekte), aber die Phasen dann jeweils einzeln im Loop: Für die 2771 Projekte werden die Phasen durch den Zugriff via OCL im Loop einzeln reingeladen, was erneute 2771 Datenbankabfragen bedeutet.

Optimierung 2: Auch die gewünschten Projektphasen werden via SQL preloaded
projekte = vtcapp.getwithsql("Projekt", "bold_id IN (SELECT projekt FROM projektphase WHERE status=1)", "")
phasen = vtcapp.getwithsql("Projektphase", "projekt in (SELECT projekt FROM projektphase WHERE status=1)", "")
for projekt in projekte:
    x = projekt.evalocl("phasen->select(status=1)")

Dauer: 20s. Eine minimale Verbesserung, die grösser ausfallen würde bei Performanceproblemen auf dem SQL-Server oder Netzwerklatenz.

Es werden alle Projekte und Projektphasen reingeladen, aber der Multilink Projekt - Phasen ist nicht "current", d.h. der Link selber weiss nicht, ob er aktuell ist, und muss deshalb einzeln nachgeladen werden mit SQL's wie:

SELECT BOLD_ID, BOLD_TYPE
FROM ProjektPhase
WHERE (Projekt in (1234567))
Optimierung 3: Versuch, den Multilink ebenfalls "current" zu machen.
phasen = vtcapp.getwithsql("Projektphase", "projekt in (SELECT projekt FROM projektphase WHERE status=1)", "")
projekte = phasen.evalocl("projekt")
for projekt in projekte:
    x = projekt.evalocl("phasen->select(status=1)")

Dauer: 21s. Keine Verbesserung, es wird trotzdem für jedes Projekt ein SQL wie oben abgesetzt. Von den Phasen her ist das Projekt zwar geladen, aber das Projekt selber weiss nicht, ob es wirklich alle Phasen schon hat.

Optimierung 4: mit vtcapp.fetchlinkmembers()

Das vtcapp.fetchlinkmembers() lädt für eine Liste von Objekten die Zielobjekte rein und macht zusätzlich den Multilink current:

projekte = vtcapp.getwithsql("Projekt", "bold_id IN (SELECT projekt FROM projektphase WHERE status=1)", "")
vtcapp.fetchlinkmembers(projekte, "phasen")
for projekt in projekte:
    x = projekt.evalocl("phasen->select(status=1)")

Dauer: 6s! Anstatt tausende SQL's werden hier im Beispiel genau 14 SQL's abgesetzt. Die Phasen der Projekte werden alle in einem Rutsch geladen mit SQL's wie

SELECT BOLD_ID, BOLD_TYPE
FROM ProjektPhase
WHERE (Projekt in (8454783,8662955,9775921,9779498,9782341,979...

Das ist Faktor 6 schneller gegenüber der naiven Abfrage via OCL. Auf weniger performanten Umgebungen kann das noch viel mehr sein, denn jede Datenbankabfrage ist grundsätzlich teuer.

Dos and Don'ts

->select auf einer langen Liste von Objekten

Hier lohnt sich die Überlegung, ob man auch über eine kürzere Liste zum gleichen Ziel kommt.

Beispiel: Es gibt sehr viel mehr Projekte im System als Projektbearbeiter. Die Expression

projekt->select(projektleiter.name = 'Christoph Keller')

dauert darum sicher länger als die Expression

projektbearbeiter->select(name = 'Christoph Keller').eigprojekte

mit demselben Resultat.

->select nach einer Subliste eines Objekts, die erst reingeladen werden muss

Sobald auf das Attribut einer Subliste selektiert werden muss, muss auch die gesamte Subliste geladen werden, siehe dazu den Abschnitt Wie funktioniert der Zugriff via OCL .

Von vielen Objekten abhängige Objekte reinzuladen ist sehr teuer und sollte vermieden werden.

Lässt sich das nicht vermeiden, sollte mit Preloading gearbeitet werden.

Oder die entsprechenden Informationen werden auf dem Objekt selber bereitgestellt mittels Keys oder Tags . So ist wie bei den persistenten Attributen das ->select unproblematisch.

->select nach einem Zusatzfeld auf einer langen Liste

Zusatzfelder sind Sublisten und nicht "Felder" auf dem Objekt, wie der Name suggeriert.

Das Filtern nach Zusatzfeldern ist sehr ineffizient, wenn die Zusatzfelder noch nicht reingeladen sind, weil sie einzeln für jedes Objekt reingeladen werden müssen.

Deshalb geht man bei Zusatzfeld-Filtern mit Vorteil über die Zusatzfelder. Statt:

projekt->select(zusatzfeldbool('auswahl'))

schreibt man also:

zusatzfeldklasse->select(boldid=1234567).zusatzfeldInstances
->select(wertBoolean).usereintrag->oclAsType(Projekt)

In unserem Performancevergleich mit vielen Daten (siehe oben) war die 2. Expression 180x schneller!

Mit SQL ist es noch schneller:

bold_id IN (SELECT usereintrag FROM zusatzfeld WHERE metazusatzfeld=1234567 AND wertboolean=1)

einfach ist die Liste dann nicht live, d.h. sie ändert sich nicht automatisch bei Änderungen.

Oder die entsprechenden Informationen werden statt in ein Zusatzfeld in Keys oder Tags geschrieben. So ist wie bei den persistenten Attributen das ->select unproblematisch.

Zusatzfelder in einer lange Liste darstellen

Zusatzfelder sind Sublisten, keine persistenten Attribute. Deshalb müssen sie Zeile für Zeile reingeladen werden. Bei langen Listen kann das zu einer Performanceverschlechterung führen.

Derived Attribute verwenden statt OCL ausformulieren

Es gibt in Vertec diverse derived Attribute , insbesondere Summenattribute, welche einen Performancevorteil bringen können gegenüber dem Ausformulieren derselben Abfrage via OCL.

Beispiel: Auf einer Tätigkeitszuordnung zu einer Phase (taetigkeitphaselink) soll der darauf erbrachte Aufwand summiert werden:

taetigkeitphaselink.evalocl("phasen.leistungen->select(typ.code='ADM').minutenInt->sum")

Es gibt auf dem taetigkeitphaselink dafür das Summenattribut sumMinutenInt. Wird stattdessen das Attribut verwendet:

taetigkeitphaselink.sumMinutenInt

erreicht man eine mehr als doppelt so schnelle Antwort.

->select nach einem derived Attribut, das berechnet werden muss

Ein ->select nach einem derived Attribut dauert beim ersten Mal länger als ein ->select auf ein persistentes Member, da es berechnet werden muss.

In den allermeisten Fällen ist dies jedoch schneller als den gleichen Aufruf selbst zu formulieren (siehe oben). Ausserdem wird es bei erneutem Aufruf nicht nochmal berechnet, sofern sich im System nichts geändert hat.

derived Attribute in einer langen Liste darstellen

Derived Attribute werden zur Laufzeit bei Anzeige berechnet. Das geschieht Zeile für Zeile, und je länger die Liste, desto mehr Zeit wird benötigt.

Es ist besser, ein derived Attribut anzuzeigen, als denselben Wert via OCL zu berechnen (siehe oben), es lohnt sich jedoch die Überlegung, ob auf die Spalte verzichtet werden kann.

Leistungssummen verwenden statt Leistungen summieren

Das Laden und Summieren von Leistungen benötigt viel Zeit, da es normalerweise sehr viele Leistungen im System gibt.

Um das zu optimieren, stehen Leistungssummen für eine beschleunigte Summierung und Gruppierung in Form von OCL Operatoren zu Verfügung.

In Listenspalten sollten sie jedoch nicht direkt verwendet werden, da sie sich, solange sie angezeigt werden, neu berechnen, wenn irgendeine Leistung im System verändert wird.

In Listenspalten kann dafür ein List Controller eingesetzt und via Custom Renderer darauf zugegriffen werden.

Spalten summieren

Listen in Vertec werden optimiert geladen: Es werden jeweils nur die sichtbaren Objekte plus eine "Seite" geladen. Beim Scrollen werden dann nach und nach die benötigten Objekte nachgeladen.

Das funktioniert nur, wenn es keine summierten Spalten hat. Denn um einen Summenwert zu bilden, müssen alle Objekte geladen werden.

Spalten umsortieren

Listen in Vertec werden optimiert geladen: Es werden jeweils nur die sichtbaren Objekte plus eine "Seite" geladen. Beim Scrollen werden dann nach und nach die benötigten Objekte nachgeladen.

Wird eine Liste jedoch umsortiert, müssen alle Objekte auf einmal geladen werden. Bei langen Listen kann das Umsortieren dann spürbar lange dauern.

Deshalb am besten die Standardsortierung so wählen, dass sie passt und nicht manuell umsortiert werden muss.

->asset nur wenn es sein muss

Der OCL Listenoperator ->asset stellt sicher, dass jedes Objekt in der Liste nur einmal vorkommt. Es ist aber teuer, weil nochmal jedes Objekt in der Liste durchgegangen, mit allen anderen Objekten in der Liste verglichen und allenfalls aussortiert werden muss.

Deshalb sollte man das ->asset nur verwenden, wenn ein Objekt überhaupt mehrmals in der Liste sein kann. Also nicht auf Vorrat verwenden, sondern die Expression analysieren und nur wenn nötig verwenden.

Business Intelligence statt Auswertungslisten

Mit dem Modul Business Intelligence (BI) können alle Daten in Vertec ausgewertet werden. Dabei werden die Daten vorberechnet, damit auch Auswertungen über längere Zeiträume und mit grossen Datenmengen performant angezeigt werden können.

Eine Vielzahl von Kennzahlen werden standardmässig schon mitgeliefert oder via Plug-ins bereitgestellt. Auch eigene Kennzahlen können hinzugefügt werden.

Das BI bietet somit eine performante Alternative zu Auswertungslisten und kann dabei noch viel mehr als eine Liste, z.B. Daten gruppiert und in Zeitreihen anzuzeigen.

Bitte wählen Sie Ihren Standort