Asynchronous includes
The easiest solution for performance improvements is to make includes “asynchronous”. As a result, the following happens:
Workplace loads the requested object by the user
Workplace shows the object to the user
Once the loading of the object is done, Workplace starts to load the includes
Once the data in an include is loaded, the data is presented. This happens for all the includes at the same time (so a small include will be shown earlier than a large include)
This is compared to the default behavior:
Workplace loads the requested object by the user
Workplace loads all includes associated with the object by the user
Once all the loading is done, the user is presented with all the data at once
Even though the total performance on the server will not be improved, the PERCEIVED performance by the user will be improved.
For setting includes to be asynchronous, open the page definition, scroll down the includes include and either select all and change the value for asynchronous to “yes”, or open the ones that you would like to change and set the value to “yes”.
Dropdown fields
Dropdown fields are a nice way to present users with a specific set of values. It might also be a performance killer in case the filter behind the dropdown field is not correct. A common example is when creating a client specific field which ends with CodeTypeId. If Workplace cannot find the associated CodeTypeScheme, and you set the field to be displayed as a dropdown, it will return ALL the codetypes as possible options. Another example is when making a dropdown with Contacts which depend on the current object (for example a Workorder), but presenting that field in a report where there is no Workorder in the context (as you are on a report). The dropdown would then consist of all Contacts.
When implementing a dropdown field, take the following steps:
Create the field with which you can select an object (this is the only case where performance issues arrive)
Make sure the field is set to “object selection screen”
Add a filter if required
Navigate to the object or report and fill in the field. You should be presented with the set object selection screen. Run it “as is”. If everything went well, you should be presented with the values that you expect. If not, you know you have made a mistake and you can rectify it.
Once you get the result that you want, change the field to “object dropdown”
When analyzing a performance problem, always check the page for dropdowns. Check how many values are in there. In case of client specific fields, double check the filters and optional scripts that retrieve the values to see if there are suboptimal queries in those.
Large reports/includes
This one should be quite obvious, but reports with a lot of result with negatively impact the performance. Especially if these are added as an include to an object. If, for whatever reason, an asynchronous include is not possible, consider changing the filtering on these reports to give back a more limited set of data. This is mostly a functional decision:
Make sure large reports are run manually, so the user is aware of the report taking a long time
See if you can scale down the amount of data on an include, as an include should only present the user with data that is relevant for that object at that time
If you have dashboards for users, limit the amount of data on those (as well as make then asynchronous)
Scripting in reports
...
Asynchroon omvat
De eenvoudigste oplossing voor prestatieverbeteringen is om includes "asynchroon" te maken. Hierdoor gebeurt het volgende:
Workplace laadt het aangevraagde object door de gebruiker
Workplace toont het object aan de gebruiker
Zodra het laden van het object is voltooid, begint Workplace met het laden van de includes
Zodra de gegevens in een include zijn geladen, worden de gegevens gepresenteerd. Dit gebeurt voor alle includes tegelijk (dus een kleine include wordt eerder getoond dan een grote include)
Dit wordt vergeleken met het standaardgedrag:
Workplace laadt het aangevraagde object door de gebruiker
Workplace laadt alle includes die door de gebruiker aan het object zijn gekoppeld
Zodra het laden klaar is, krijgt de gebruiker alle gegevens in één keer te zien.
Ook al zal de totale prestatie op de server niet verbeteren, de PERCEIVED prestatie door de gebruiker zal wel verbeteren.
Als u wilt instellen dat includes asynchroon zijn, opent u de paginadefinitie, scrollt u naar beneden door de includes en selecteert u alles en wijzigt u de waarde voor asynchroon in "ja", of opent u de includes die u wilt wijzigen en stelt u de waarde in op "ja".
Dropdown velden
Dropdown-velden zijn een mooie manier om gebruikers een specifieke reeks waarden te presenteren. Het kan ook de prestaties ondermijnen als het filter achter het dropdown veld niet correct is. Een veelvoorkomend voorbeeld is wanneer je een klantspecifiek veld maakt dat eindigt op CodeTypeId. Als Workplace het bijbehorende CodeTypeSchema niet kan vinden en je het veld instelt om als dropdown weer te geven, zal het ALLE codetypes als mogelijke opties retourneren. Een ander voorbeeld is bij het maken van een dropdown met Contacten die afhankelijk zijn van het huidige object (bijvoorbeeld een Werkorder), maar het presenteren van dat veld in een rapport waar er geen Werkorder in de context is (omdat je op een rapport bent). De dropdown zou dan bestaan uit alle Contactpersonen.
Neem de volgende stappen bij het implementeren van een vervolgkeuzemenu:
Maak het veld aan waarmee je een object kunt selecteren (dit is het enige geval waarbij prestatieproblemen optreden)
Zorg ervoor dat het veld is ingesteld op "object selectiescherm".
Voeg indien nodig een filter toe
Navigeer naar het object of rapport en vul het veld in. Je krijgt nu het selectiescherm voor het object te zien. Voer het uit "zoals het is". Als alles goed is gegaan, krijg je de waarden te zien die je verwacht. Zo niet, dan weet je dat je een fout hebt gemaakt en kun je deze herstellen.
Zodra je het gewenste resultaat hebt, verander je het veld in "object dropdown".
Controleer bij het analyseren van een prestatieprobleem altijd de pagina op dropdowns. Controleer hoeveel waarden daarin staan. Als het om client-specifieke velden gaat, controleer dan de filters en optionele scripts waarmee de waarden worden opgehaald om te zien of daar suboptimale query's in zitten.
Grote rapporten
Deze zou vrij voor de hand moeten liggen, maar rapporten met veel resultaten hebben een negatieve invloed op de prestaties. Vooral als deze worden toegevoegd als een include aan een object. Als, om wat voor reden dan ook, een asynchrone include niet mogelijk is, overweeg dan om de filtering op deze rapporten te veranderen zodat ze een beperktere set gegevens teruggeven. Dit is vooral een functionele beslissing:
Zorg ervoor dat grote rapporten handmatig worden uitgevoerd, zodat de gebruiker weet dat het rapport lang duurt
Kijk of je de hoeveelheid gegevens op een include kunt verkleinen, want een include moet de gebruiker alleen gegevens tonen die op dat moment relevant zijn voor dat object.
Als je dashboards hebt voor gebruikers, beperk dan de hoeveelheid gegevens daarop (en maak ze asynchroon)
Scripts in rapporten
In rapporten kan scripting worden gebruikt om indien nodig complexere formules uit te voeren. Een formule zou er als volgt uit kunnen zien:
Code Block |
---|
execute("MakeComplexCalculation",WorkorderReference) |
There is one downside to this: when passing values to the script (in the above case, “WorkorderReference”), these are passed as strings, NOT as objects. So that results in the scripting having to perform a second query based on the value. To sketch a hypothetical case:
A report returns 100 workorders
Based on those workorders, you pass the workorder reference to the formula script
You than do a query on the workorder reference, from which you get the values from the workorder and return a calculated value
The above situation results in 101 queries: one for the report, 100 for each consecutive line for which you make the calculation. A more performant option is to add all the necessary values that you need in the script in the report, hide them from the end result, but pass them to the formula. The formula call would be the followingEr is één nadeel: wanneer je waarden doorgeeft aan het script (in het bovenstaande geval "WorkorderReference"), worden deze doorgegeven als strings, NIET als objecten. Dat heeft dus tot gevolg dat het script een tweede query moet uitvoeren op basis van de waarde. Om een hypothetisch geval te schetsen:
Een rapport geeft 100 werkorders
Op basis van die werkorders geeft u de werkorderreferentie door aan het formulescript
Vervolgens doe je een query op de werkorderreferentie, waaruit je de waarden van de werkorder haalt en een berekende waarde retourneert
De bovenstaande situatie resulteert in 101 queries: één voor het rapport, 100 voor elke opeenvolgende regel waarvoor je de berekening maakt. Een meer performante optie is om alle benodigde waarden die u nodig hebt in het script toe te voegen aan het rapport, ze te verbergen voor het eindresultaat, maar ze door te geven aan de formule. De formuleaanroep zou er als volgt uitzien:
Code Block |
---|
execute("MakeComplexCalculation",WorkorderPlannedAmount,WorkorderInvoicedAmount,WorkorderSupplierMultiplier) |
In the script, you would then use the het script gebruik je dan de (string!) values to make the necessary calculations. This will result in 1 query for the complete report.
Client specific fields
Every time you create a client specific field, this results in an additional database call for every object made which has that field on it. At certain points, this becomes a performance killer (experience learns this is about 80 client specific fields where this becomes quite slow). So take the following aspects into consideration when creating client specific fields (or when debugging performance):
...
Make client specific fields on the lowest category possible. That will result in the fields only being created for a specific subset of objects
...
Only put a client specific field on a higher category level if more than 3 sub categories need it OR the subcategories in combination with the parent category are a limited subset
...
Look at the existing fields and see if you can re-use a field or not
...
Cleanup fields that are no longer used
...
waarden om de nodige berekeningen te maken. Dit resulteert in 1 query voor het volledige rapport.
Klantspecifieke velden
Elke keer dat je een client-specifiek veld aanmaakt, resulteert dit in een extra database-aanroep voor elk object dat dat veld heeft. Op bepaalde momenten wordt dit een prestatie-killer (de ervaring leert dat dit bij ongeveer 80 clientspecifieke velden vrij traag wordt). Houd dus rekening met de volgende aspecten bij het maken van clientspecifieke velden (of bij het debuggen van de prestaties):
Maak klantspecifieke velden op de laagst mogelijke categorie. Dat zorgt ervoor dat de velden alleen worden gemaakt voor een specifieke subset van objecten.
Zet een klantspecifiek veld alleen op een hoger categorieniveau als meer dan 3 subcategorieën het nodig hebben OF de subcategorieën in combinatie met de hoofdcategorie een beperkte subset zijn
Bekijk de bestaande velden en kijk of je een veld kunt hergebruiken of niet
Opschonen van velden die niet meer worden gebruikt
Als er veel verschillende velden nodig zijn, overweeg dan het gebruik van een onafhankelijk object (bijv. CodeType) met een specifieke categorie om de velden op te plaatsen. Dit voorkomt onnodige velden op een specifiek object. Het kan ook resulteren in de mogelijkheid om het onafhankelijke object op een later tijdstip te maken, wat de impact op de prestaties vermindert bij het aanvankelijk maken van het object.