The most important thing is to remember where and when to write the code.
a. Developers have an inherent habit of writing erratic select statements:
select * from custTable
where custTable.AccountNum == <SomeValue>
Where in essence we need to make use of optimized choice of fields in the select statement.
b. Making use of 'continue' keywords:
While select custTrans
where <someConditions>
{
if (cusTTrans.CustGroup != mappingTable.CustGroup)
{
continue;
}
}
'Continue' statements are precisely a very unhygienic way of designing your code. The above statement could have been easily ornamented by using exists/not exists joins. Using Continue statements would eventually result in a high performance impact. Also select statements should be made punctuated with a 'firstonly' clause -- just not from best practise standpoint, but also from performance considerations.
c. Writing nested loops:
This is a common mistake that perhaps every developer makes by nestling one loop inside another loop and then to make things all the more worse, making an insert call again and again in the loop:
While select custTrans
where <some conditions>
{
while select GeneralJournalEntry
where GeneralJournalEntry.AccountingDate == custTrans.TransDate
{
tmpCustAllocTable.AccountingDate = custTrans.TransDate;
tmpCustAllocTable.CustAccount = custTrans.AccountNum;
tmpCustAllocTable.insert();
}
}
What a mess, O' Rama! 👺👺
This could have been easily cut down by using a join statement, using an insert_recordset/or using a recordInsertList. Precalculated views could also offer to work as an excellent mode of speeding up your calculations, when you have a voluminous data exchange.
e. Writing server-side calculations on clicked events/client-side events:
This is also a very bad habit of calling your server-side calculations from client-side processes, which you could easily avoid by manipulating a little with the associated action menuitems that calls the process [e.g.: I remember, in my yesteryears, we had a requirement of creating/updating records in a custom table, while confirming a purchase order. I still remember our tech lead asked us to write the entire logic in the clicked event of the form. This should have rather been managed from the class: PurchOrderJournalCreate\\endPost method -- that ensures the process has been successfully completed.]
In fact you should avoid writing as much as code as possible on forms -- transfer all your execution at server end: 'runat' keywords could also be used here (but yes, wisely 💀💀💀)
f. Writing Find methods inside loop:
For example, the below code:
While select custTrans
where <some conditions>
{
CustGroup custGroup = CustGroup::find(custTrans.CustGroup);
//rest part of the code
}
This once again, could cause a huge performance impact, instead if we can join the buffer with the outer main loop, with the only selected fields' set, for a better results perspective.
g. Minimisig CRUD operations on loops as much as possible:
What's wrong with the below code:
While select custTrans
where <some conditions>
{
//some pre-processing
select for update custAllocationTable
where custAllocationTable.AccountTable == custTrans.RecId;
if (custAllocationTable)
{
custAllocationTable.foreignAccount = custTrans.ForeignAccount;
custAllocationTable.update();
}
}
With 10.0.25, we have a powerful keyword 'In' that can help us to speed up the same by picking up all the <t>custTrans<t> in a container and then coming out of the loop and then separately updating custAllocationTable directly by using the 'IN' statement.
h. The parent and children table:
This is also a potential area of mishap. We always insert first on parent tables first and then loop through the staging records to insert into children tables, whence all these could be best avoided by wisely using the UnitOfWork framework, which expects it to just specify who is the parent and who are the children and then you rest it leave it up the framework to take care. Honestly, UnitOfWork is one of the most underrated tools of development, that many developers don't even know of.
i. Meaningless use of 'Index hints':
Yes, this has been deprecated from Ax2012, yet many developers think it to be a religious habit to use index hints in their select statements. Likewise you also don't need to punctuate your variable declaration section with a ';' syntax -- it's no longer needed too.
J. Missing table properties:
This is a very commonly followed bad habit of leaving most of table properties empty (table relations, table groups, delete actions, configuratiion keys, cache lookup/wrong combination of cache lookup and table group combination).
K. Most important part: improper key index:
Also, not to mention, a proper Indexing of the table needs to be done, depending on the data structures, data patterns and other parameters. They have just don't have a major impact on the performance, but also tells a lot on how the system should behave, retrieve and interact.
L.Nitro boosting your processing speed with views
Inspect the code, see how the flow Kinesis is behaving from one control to the next. If your data is way too high, you can wisely make use of a view, with proper selection of fields.
Below is an example that can help you improvise your processing speed by faithfully dodging the repetitive calculations of customer wise, yearly balances -
https://subsd365.blogspot.com/2023/04/year-wise-data-for-faster-execution-in.html
Likewise you can also engineer your code to preprocess everything beforehand and make the processing speed improve drastically.
Lastly, we can speed up performance by cutting down X++ code, by introducing more of Power platform based processes, whereby you can consume your X++ codes as CodeUnits and directly use them from 'Power objects'.
It's easy and certainly involves a low cost of maintenance.
*This post is locked for comments