Impact automatic cost adjustment with Business Central

Impact automatic cost adjustment

When working with high-volume Business Central environments in a SaaS environment, one of the most overlooked performance bottlenecks is the automatic cost adjustment process. This blog post is about diagnosing performance impact of automatic cost adjustment using KQL. Especially in intercompany-heavy setups, this background process can silently overload your system—causing job queues to pile up and users to experience slowdowns.

In this post, we’ll walk through how to use Kusto Query Language (KQL) to identify and visualize the impact of automatic cost adjustments using Application Insights telemetry.

Filter for Cost Adjustment records

let _startTime = datetime(2025-05-20T08:30:00Z);
let _endTime = datetime(2025-05-20T17:00:00Z);
let _aadTenantId = "84d30a91-7218-4db6-b27d-acc36edf7c3d";
let _environmentName = "Production";
let _environmentType = "Production";
traces
| where timestamp between (_startTime.._endTime)
| where customDimensions.aadTenantId == _aadTenantId
| where customDimensions.environmentType == _environmentType
| where customDimensions.environmentName == _environmentName
| where severityLevel > 0
| extend messageText = tostring(message)
| where messageText has "cost adjust" or messageText has "cost adjustment" or messageText has "automatic cost"
| extend company = tostring(customDimensions.companyName)

This gives the number of records where telemetry tells us automatic costing was running due to inventory change.

ValueCounted value
Automatic cost adjustment was used7596
Table with number of records

As you can see, during one day, there were 7593 times automatic cost adjusting ran. We can also split these per company to get more insights.

let _startTime = datetime(2025-05-20T08:30:00Z);
let _endTime = datetime(2025-05-20T17:00:00Z);
let _aadTenantId = "84d30a91-7218-4db6-b27d-acc36edf7c3d";
let _environmentName = "Production";
let _environmentType = "Production";
traces
| where timestamp between (_startTime.._endTime)
| where customDimensions.aadTenantId == _aadTenantId
| where customDimensions.environmentType == _environmentType
| where customDimensions.environmentName == _environmentName
| where severityLevel > 0
| extend messageText = tostring(message)
| where messageText has "cost adjust" or messageText has "cost adjustment" or messageText has "automatic cost"
| extend company = tostring(customDimensions.companyName)
| summarize CostAdjustCount = count() by (company)

The results are like this.

ValueCounted value
CompanyA60
CompanyB2977
CompanyC24
CompanyD1558
CompanyE78
CompanyF2899
Table with number of records

What is automatic cost adjustment

Cost adjustment can be performed in two ways:

  • Manually, by running the Adjust Cost – Item Entries batch job. You can run this batch job either for all items or for only certain items or item categories. This batch job runs a cost adjustment for the items in inventory for which an inbound transaction has been made, such as a purchase. For items that use the average costing method, the batch job also makes an adjustment if any outbound transactions are created.
  • Automatically, by adjusting costs every time that you post an inventory transaction, and when you finish a production order. The cost adjustment is only run for the specific item or items affected by the posting. This is set up when you select the Automatic Cost Adjustment check box on the Inventory Setup page.

It is good practice to run the cost adjustment automatically when you post because unit costs are more frequently updated and therefore more accurate. The disadvantage is that the performance of the database can be affected by running the cost adjustment so often.

Because it is important to keep the unit cost of an item up to date, it is recommend that you run the Adjust Cost – Item Entries batch job as often as possible, during nonworking hours. Alternatively, use automatic cost adjustment. This ensures that the unit cost is updated for items daily.

Impact automatic cost adjustment

Regardless if you run the cost adjustment manually or automatically, the adjustment process and its consequences are the same. Business Central calculates the value of the inbound transaction and forwards that cost to any outbound transactions, such as sales or consumptions, which have been applied to the inbound transaction. The cost adjustment creates value entries that contain adjustment amounts and amounts that compensate for rounding.

The new adjustment and rounding value entries have the posting date of the related invoice. Exceptions are if the value entries fall in a closed accounting period or inventory period or if the posting date is earlier than the date in the Allow Posting From field on the General Ledger Setup page. If this occurs, the batch job assigns the posting date as the first date of the next open period.

Real live scenario

In the scenario, I worked on. There was a company with a few branch offices. The main company had the responsibility of keeping the inventory. Via master data management, the items were replicated to the branches. Via job queues, purchase orders and sales orders were automatically created and synched again. Having said that, the inventory levels at the branches were always 0 while the main company was maintaining the inventory correctly.

Setting the automatic cost adjustment to always was not advised in this scenario as telemetry shows the following events.

Telemetry

timestampmessagealDetailedErrorMessageseverityLeveleventIdextension
2025-05-20 12:01:55.8100058Operation exceeded time threshold (SQL query)2RT0005Microsoft
timestamp:	2025-05-20 12:01:55.810
message:	Operation exceeded time threshold (SQL query)
alDetailedErrorMessage:	
severityLevel:	2
eventId:	RT0005
alObjectId:	472
alStackTrace:	AppObjectType: Table
  AppObjectId: 472
  AL CallStack: "Job Queue Entry"(Table 472).ActivateNextJobInCategory line 11 - Base Application by Microsoft version 26.0.30643.34008
"Job Queue Entry"(Table 472).ActivateNextJobInCategory line 8 - Base Application by Microsoft version 26.0.30643.34008
"Job Queue Activate Next"(CodeUnit 462).OnRun(Trigger) line 2 - Base Application by Microsoft version 26.0.30643.34008
"Job Queue Entry"(Table 472).ActivateNextJobInCategoryIfAny line 9 - Base Application by Microsoft version 26.0.30643.34008
"Job Queue Dispatcher"(CodeUnit 448).OnRun(Trigger) line 25 - Base Application by Microsoft version 26.0.30643.34008
extension:	Microsoft
customDimensions:	{
  "component": "Dynamics 365 Business Central Server",
  "alObjectId": "472",
  "extensionPublisher": "Microsoft",
  "alObjectType": "Table",
  "eventId": "RT0005",
  "telemetrySchemaVersion": "0.5",
  "extensionName": "Base Application",
  "companyName": "CompanyA",
  "environmentName": "Production",
  "componentVersion": "26.0.33865.0",
  "clientType": "Background",
  "extensionVersion": "26.0.30643.34008",
  "aadTenantId": "84d30a91-7218-4db6-b27d-acc36edf7c3d",
  "alObjectName": "Job Queue Entry",
  "extensionId": "437dbf0e-84ff-417a-965d-ed2bb9650972",
  "environmentType": "Production",
  "sqlStatement": "SELECT...
}

You can easily view the information about the event here.

RT0005PerformanceOperation exceeded time threshold (SQL query)
  1. Set Automatic Cost Adjustment to “Never”

    Every time a purchase order is posted, the system otherwise tries to immediately adjust the cost prices of related items and transactions. With many transactions, this leads to performance issues, delays, and potential locking.

    Recommended alternative: Schedule a periodic task (e.g., at night or outside peak hours) that runs the “Adjust Cost – Item Entries” batch job.
  2. Use a batch job for cost adjustment. Run the “Adjust Costs – Item Entries” task (codeunit 5895) regularly as a job queue, for example:
    • Daily at night
    • After completing a batch of purchase order processing
      This keeps costs accurate without putting real-time load on your system.
  3. Be cautious with FIFO/LIFO/Standard Costing
    Especially with FIFO or LIFO costing models, it’s crucial to continue adjusting costs accurately via the batch job, since later sales are linked to earlier purchase prices.
  4. Inform users about delays in cost prices
    Since costs are not adjusted immediately, users may temporarily see incorrect cost prices in reports. This is normal behavior as long as the batch job has not yet been executed.

Visualizing the impact of automatic cost adjustment

We can also visualize the above via KQL The query then looks like this showing the impact of automatic cost adjustment

// Customer Name: Contoso
// Tenant Id 84d30a91-7218-4db6-b27d-acc36edf7c3d
let _startTime = datetime(2025-05-19T07:00:00Z);
let _endTime = datetime(2025-05-20T23:59:00Z);
let _aadTenantId = "84d30a91-7218-4db6-b27d-acc36edf7c3d";
let _environmentName = "Production";
let _environmentType = "Production";
traces
| where timestamp between (_startTime.._endTime)
| where customDimensions.aadTenantId == _aadTenantId
| where customDimensions.environmentType == _environmentType
| where customDimensions.environmentName == _environmentName
| where severityLevel > 0
| extend messageText = tostring(message)
| where messageText has "cost adjust" or messageText has "cost adjustment" or messageText has "automatic cost"
| project 
    timestamp,
    message,
    alDetailedErrorMessage = customDimensions.alDetailedErrorMessage,
    severityLevel,
    eventId = customDimensions.eventId,
    alObjectId = customDimensions.alObjectId,
    alStackTrace = customDimensions.alStackTrace,
    extension = customDimensions.extensionPublisher,
    company = customDimensions.companyName
|summarize count() by bin(timestamp, 1h)
| render timechart

And the line graph. It is unfortunately not possible with Kusto Explorer to name the X-axis and Y-axis but we are summarizing the number of automatic cost adjustments in a time frame of one day split per hour. You can t hen easily see how much impact automatic cost adjustment may have in the environment.

More information about Business Central can be found here.

0 Shares:
You May Also Like