Showing posts with label performance. Show all posts
Showing posts with label performance. Show all posts

Wednesday, December 7, 2022

D365FO: Bypassing "next" in CoC

DISCLAIMER: Use this trick at your own risk. Do not do this, unless you absolutely have to. 

Some time ago I had to figure out why one of the custom services was slow. It took like 30+ seconds to return a dozen of trade agreements for a customer.

It turned out the SysExtension framework tried to collect data about classes through reflection, and it did that multiple times in the same session. 

The issue may be reproduced with this runnable class. Here, we instantiate instances of 4 different classes. The class constructors use SysExtension framework for figuring out which class type to build.


If running the class the first time, the output would look something like this:

SalesLineType::construct: 13610 ms
SalesSummaryFields::construct: 1968 ms
SalesQuantity::construct: 2078 ms
TradeModuleType::newFromModule: 3406 ms

After System administration -> Setup -> Refresh elements, the time would drop to:

SalesLineType::construct: 1735 ms
SalesSummaryFields::construct: 1781 ms
SalesQuantity::construct: 1641 ms
TradeModuleType::newFromModule: 1656 ms

But still, almost 2 seconds for every single class instance is too much. 

The following change can fix this issue by skipping metadata collection, if it is already done:


This code does the following: if the reflection is already collected (reflectionDataEnumerator.moveNext() returns "true"), we throw an exception of a type, that will most likely never be thrown from the "next populateFromMetadata();" itself. Then, we catch the exception, but that also means the "next" statement is skipped and the reflection cache data is not built from scratch again. 

After this change, the runnable class output looks like this:

SalesLineType::construct: 1657 ms
SalesSummaryFields::construct: 218 ms
SalesQuantity::construct: 125 ms
TradeModuleType::newFromModule: 157 ms

It is important, that this "skip" is only done when there is no transaction scope around, otherwise it would abort the transaction, therefore the check for ttsLevel. So, this trick will basically improve performance of certain "read" scenarios, but in order to improve performance for "write" scenarios, MS has to provide a fix.

Tuesday, October 27, 2015

When fields lists don't work as expected

Did you know that a field list in a single-record select-statement is not always beneficial in comparison to a select firstonly * from...  (or a static find-method)?

The thing is, when a where-clause matches a unique index (in AX 2009 – a primary index), the AOS may find the complete record in the cache and return it. And if this is the very first call, it will pull the whole record anyway, in order to be able to cache it. This may be proved by debugging.

So please use find-methods where possible, because they are easier to read and maintain. And remember: a while select with a nested find-method call may actually perform better than a join – thanks to caching. Therefore do measure performance to confirm that your select-statement is the most optimal one.

Wednesday, April 9, 2014

Sales invoices in batch: performance issue solved

Our customer experienced huge performance problems with posting sales invoices in batch.

Teh customer had multiple recurring batch jobs run in their headquarter company. Each batch job processed intercompany sales orders corresponding to a particular regional office. They put the jobs to different batch groups and allocated separate AOSes for those groups.

At some point, the code in production has changed, but the batch jobs have never been recreated. It looks like version of their parameters became outdated and therefore the ranges were ignored at run time, and that resulted in all jobs trying to post all invoices. After their AX admin recreated the recurring jobs, the issue has gone.

So next time you are incrementing CurrentVersion macro in a RunBaseBatch ancestor, consider handling the old version in the unpack-method, so only new parameters will be nil after unpacking.