Back to Blog
Published:
Last Updated:
Recently Updated
ERP Write-Back & IntegrationChapter 1

Why does your OData integration slow down at a few thousand records an hour?

9 min read
1,985 words
high priority
Mudassir Marwat

Mudassir Marwat

Founder & CEO, Cognilium AI

TL;DR

Microsoft's own integration sizing examples put OData at a peak data volume measured in records per hour, and the batch data API examples two orders of magnitude above it. Here is the table Microsoft publishes, the caveat it attaches, the validate chain that explains the number, and the four OData behaviours that make a working integration slower or quietly wrong.

Why does your OData integration slow down at a few thousand records an hour?

Because that is roughly where Microsoft's own published sizing examples put it. The unit in Microsoft's integration guidance is records per hour, not per minute, and behind that unit is a validation chain that runs in full on every row you send.

Before you go looking for a misconfiguration, check the pattern against the sizing Microsoft published for it.

Microsoft publishes the sizing, and it is per hour

Integration between finance and operations apps and third-party services walks six worked scenarios, each carrying a decision table with a Peak data volume line. Collected, those lines answer the question in the title.

OData (Open Data Protocol) and the batch data API are both on the page's own pattern list — long-standing [GA] platform APIs that Microsoft recommends by scenario on that page.

  • Create and update product information — Pattern Microsoft recommends: OData service endpoints · Peak data volume Microsoft states: 1,000 records per hour
  • Read the status of customer orders — Pattern Microsoft recommends: OData service endpoints · Peak data volume Microsoft states: 5,000 records per hour
  • Approve BOMs (bill of materials — the parts list for a product) — Pattern Microsoft recommends: An OData action · Peak data volume Microsoft states: 1,000 records per hour
  • Look up on-hand inventory — Pattern Microsoft recommends: A custom service · Peak data volume Microsoft states: 1,000 records per hour
  • Import large volumes of sales orders — Pattern Microsoft recommends: Batch data APIs · Peak data volume Microsoft states: 200,000 records per hour
  • Export large volumes of purchase orders — Pattern Microsoft recommends: Batch data APIs · Peak data volume Microsoft states: 300,000 records per hour

Every figure there is Microsoft's, from the same page. The highest volume it attaches to an OData scenario is the customer-order status read; the lowest it attaches to a batch data API scenario is forty times that. That gap is the design decision, visible on one page before anyone writes a line of code.

The caveat Microsoft attaches, and the threshold it publishes

Do not sharpen those numbers. Microsoft's own note, in full:

When providing guidance and discussing scenarios for choosing a pattern, data volume numbers are mentioned. Use these numbers only to gauge the pattern and don't consider them as hard system limits. The absolute numbers vary in real production environments because of different factors—configurations are only one aspect of this scenario.

They size an architecture. They do not certify one. The same page also publishes a threshold, stated as guidance rather than as a measurement:

Batch data APIs are designed to handle large-volume data imports and exports. It's difficult to define what exactly qualifies as a large volume. The answer depends on the entity, and on the amount of business logic that is run during import or export. However, here's a rule of thumb: If the volume is more than a few hundred thousand records, use the batch data API for integrations.

Note what the rule of thumb does not say. It does not say OData is safe up to a few hundred thousand records. It names the point past which the question is settled. Below it, the sizing table is what you have.

Why the number is what it is: every row runs the validate chain

OData is synchronous, and Microsoft states the consequence plainly: "Both OData and custom services are synchronous integration patterns, because when you call these APIs, business logic runs immediately."

Immediately is doing the work. The OData page publishes the methods "that the OData stack implicitly calls on the corresponding data entity", in order, per operation.

  • Create — Methods Microsoft lists, in the order it lists them: Clear() · Initvalue() · PropertyInfo.SetValue() for all specified fields in the request · Validatefield() · Defaultrow · Validatewrite() · Write() · Steps: seven
  • Update — Methods Microsoft lists, in the order it lists them: Forupdate() · Reread() · Clear() · Initvalue() · PropertyInfo.SetValue() for all specified fields in the request · Validatefield() · Defaultrow() · Validatewrite() · Write() · Steps: nine
  • Delete — Methods Microsoft lists, in the order it lists them: Forupdate() · Reread() · checkRestrictedDeleteActions() · Validatedelete() · Delete() · Steps: five

An update takes an update lock and re-reads the record — Forupdate(), then Reread() — before a single field is set. Then it validates the field, defaults the row, and validates the write.

That is X++ (the Finance and Operations development language) business logic, per row, per call, and it is why Microsoft sizes these scenarios in an hour rather than a minute.

(Defaultrow appears without parentheses on Microsoft's Create row and with them on its Update row; both are reproduced as published.)

This is also why adding threads plateaus once the per-row operation stops being a quick one. You are not queueing behind network latency. You are queueing behind the ERP's own posting logic, which is the thing you wanted to run.

Four OData behaviours that make it slower, or quietly wrong

Each of these is on Microsoft's OData page, and each is cheap to fix before go-live and expensive after.

  • Cross-company is off — What Microsoft's page says: "By default, OData returns only data that belongs to the user's default company. To see data from outside the user's default company, specify the ?cross-company=true query option." · What it costs you: A multi-entity manufacturer gets one company's data and a green test run
  • $expand is shallow — What Microsoft's page says: The supported query options include "$expand (only first-level expansion is supported)" · What it costs you: Second-level reads become separate calls against the same per-hour scenario volume
  • The client posts what you did not set (on create) — What Microsoft's page says: "When you create a new record by using an OData client… the client includes properties that you don't set in the body of the request and assigns default values to them" · What it costs you: A newly created record carries defaults in every field the client did not set
  • Paging has a ceiling — What Microsoft's page says: "The OData service supports serving driven paging with a maximum page size of 10,000" · What it costs you: Page-size tuning stops helping at a published number

The fix for the third is the highest-value line here: SaveChangesOptions.PostOnlySetProperties on SaveChanges(), with before-and-after code on the same page. And to filter to one company rather than opening all of them, Microsoft's syntax is ?$filter=dataAreaId eq 'usrt'&cross-company=true — the filter alone will not do it.

Business Central publishes a read-replica intent. These four Finance and Operations pages do not.

If your write path is Business Central rather than Finance and Operations, there is a documented way to move read traffic off the primary database.

Read Scale-Out [GA] is marked "INTRODUCED IN: Business Central 2020 release wave 1", and the DataAccessIntent property [GA] that drives it is "Available or changed with runtime version 5.0".

It applies to Page, Report and Query objects, and, when calling an API page or API query, a caller overrides it per request with the HTTP request header Data-Access-Intent.

Then read the hedges, because they are the engineering story. "In the Business Central Online service, almost all OData GET requests use read-only intent for data access" — almost all.

And, on both pages: "Setting the DataAccessIntent property to ReadOnly doesn't guarantee that your data access will be running on the secondary replica." It is a hint, not a route.

"Sandbox environments can't be enabled with read scale-out", so what you measure in a sandbox is the primary database either way.

On the four Finance and Operations pages cited here — the integration overview, the OData page, the service protection API limits page and Maximize API throughput — none publishes an equivalent read-replica intent option for OData. That side publishes the validate chain instead.

What Microsoft says to do about throughput

Maximize API throughput is the page to argue from, and four of its six strategies are directly actionable. The fifth and sixth — distributing across multiple service principals, and connection tuning, for which Microsoft publishes sample code — are design changes rather than settings.

  • Let the server set the pace. "Don't try to calculate the number of requests that you should send at a time. Each environment can differ." Ramp until you hit limits, then follow the Retry-After interval.
  • Avoid large batches. "Most scenarios are fastest if you send single requests and use a high degree of parallelism." The ceiling is stated: "In finance and operations apps, batch size is limited to 5,000 operations."
  • Remove the affinity cookie. "If you remove the cookie, you can route each request to any eligible server. Throughput increases because limits apply per server." Microsoft's Note restricts this to applications that must optimize throughput — interactive clients lose cached data.
  • Use multiple threads — with Microsoft's condition attached, which is the same condition the validate chain above imposes: "If your individual operations are relatively quick, your application can use the higher limit on the number of concurrent threads to significantly improve performance."

The fifth — distributing work across multiple service principals — is written on that page around user-based limits, and the status of those limits changed. Read it next to the companion piece on which service protection limits are actually enforced.

Where we draw the line

We do not put bulk movement on the synchronous path, and we do not ask an ERP to be a feature store. Dynamics is the system of record; the optimization is the system of intelligence, and the two want different doors — which is why our write path uses both.

Demand & Inventory Optimizer reads history through the batch data path and writes the decision — the reorder point, the safety-stock level — back through OData, because a decision is a handful of rows and belongs where validation runs and errors return in the response. Pricing & Discount Optimizer does the same with the price on the line.

What we refuse to build: a nightly full-catalogue refresh over OData, or a model-training extract that walks the entity endpoint page by page. Those are batch data API jobs. We do not touch your ERP core — we surround it with intelligence.

What to do this week

  1. Open the six scenarios on Microsoft's integration overview and write your own peak data volume beside the closest one. If yours is an order of magnitude higher, the pattern is the finding, not the code.
  2. Grep the integration for cross-company=true. If it is absent and you run more than one legal entity, you have a correctness problem before a throughput problem.
  3. Search the client for PostOnlySetProperties. If it is absent on any path that creates master-data records, fix that before anything else here.
  4. Count the $expand calls that need a second level. Each is already a separate request; decide whether it belongs on a batch data API export instead.

About Cognilium Cognilium is the AI optimization layer for Dynamics 365 — complementary apps that optimize the pricing, inventory, warehouse and planning decisions your ERP manages but can't optimize. Built on Power Platform, Dataverse and Azure. https://cognilium.ai · https://www.linkedin.com/company/37180269/

Take your peak hourly row count to the sizing table above and see which side of it you land on. If the answer surprises you, book a fifteen-minute call and we will walk your write path with you, live — no deck. https://cognilium.ai

Sources

Sources

Share this article

The work behind this series

Six patterns, and the four published limits that actually decide which one survives production — service protection, OData throughput, business-event ordering and recurring-integration redelivery.

Mudassir Marwat

Mudassir Marwat

Founder & CEO, Cognilium AI

Mudassir Marwat's argument is that ERP systems record decisions they never optimise.

Founder & CEO of Cognilium AI; 37 AI agents in production across four products; 4 production AI products built and operated; three clouds in production (AWSGCPAzure)
Agentic AIRAG → GraphRAG retrievalVoice AIMulti-Agent Orchestration
In short

Key takeaways

  • Microsoft's published integration sizing states OData peak data volume in records per hour and batch data API peak data volume in a range far above it, on the same page, in the same units.
  • Microsoft labels those volumes as gauges for choosing a pattern rather than as hard system limits, so they size an architecture and do not certify one.
  • The reason OData throughput is what it is: Microsoft publishes the validate chain the OData stack runs per row, and an update re-reads the record before it sets a field.
  • Cross-company access is off unless the query option is present, so a multi-company ERP can return one company's data and still look correct in a single-company test.
  • The Business Central read-replica intent is a hint to the server rather than a guarantee of which replica serves a request, and Microsoft states that sandbox environments cannot be enabled with read scale-out.
What goes wrong

Common mistakes to avoid

  • Quoting Microsoft's sizing figures as certified maximums. They are published as gauges for choosing a pattern, and Microsoft says so in a note directly above them.
  • Treating the batch data API threshold as permission to use OData for everything below it. Microsoft names the point past which the question is settled, not a safe zone underneath.
  • Adding threads to an integration that is queueing behind the ERP's own validation rather than behind the network.
  • Letting the default OData client include the properties you did not set when it creates a record, which assigns default values to fields nobody meant to touch.

Still have a question this did not answer?

The person who wrote this article answers these. Describe your setup and what you are stuck on — you will get a straight answer, including where we think the approach is wrong.

Related Articles

Continue exploring related topics and insights from our content library.

9 min
1
Mudassir Marwat
August 1, 2026

Which Dynamics 365 service protection limits are actually enforced?

The three limits Dataverse actually enforces per user per server, what happens when you cross one, and why a retry loop makes it worse.

words
Read Article
7 min
2
Mudassir Marwat
August 1, 2026

Why do recurring integrations create duplicate documents?

A duplicated document from a recurring integration is a redelivery, not a lost message. Microsoft documents that an unacknowledged message becomes available to dequeue again every 30 minutes until it is acknowledged, and that the acknowledgement must echo the dequeue response body. Here is the contract in Microsoft's words, the three ways teams break it, one more path that re-serves the same message, one upgrade that breaks your defence against it, and what will not fix any of it.

words
Read Article
8 min
3
Mudassir Marwat
August 1, 2026

Business events give you no ordering guarantee. What do you build instead?

Microsoft states it under a heading called Limitations - the order in which Finance and Operations emits business events isn't guaranteed to preserve the order in which they're delivered. The control number is a dedupe key, not a sequence. So you build consumers that are idempotent, derive state from the record rather than the event sequence, and reconcile against the ERP rather than against the event stream.

words
Read Article

Explore More Insights

Discover more expert articles on AI, engineering, and technology trends.

Personalized for You

Curated content recommendations based on your current reading and interests.

Trending
116%

Business events give you no ordering guarantee. What do you build instead?

Same topic cluster: ERP Write-Back & Integration
Same author: Mudassir Marwat

Microsoft states it under a heading called Limitations - the order in which Finance and Operations emits business events isn't guaranteed to preserve the order in which they're delivered. The control number is a dedupe key, not a sequence. So you build consumers that are idempotent, derive state from the record rather than the event sequence, and reconcile against the ERP rather than against the event stream.

Mudassir Marwat
8 min read
ERP Write-Back & Integration
Read Article
Trending
37%

Why do received goods sit uninvoiced, and what can an agent actually do about it?

High priority content
Related topic cluster: Procure-to-Pay Agent Operations

Dynamics 365 already matches product receipts to invoices hourly or daily. The balance that will not clear is the residue the automation cannot resolve.

Ali Ahmed
7 min read
Procure-to-Pay Agent Operations
Read Article
Trending
116%

Is BYOD retired?

Same topic cluster: ERP Write-Back & Integration
Same author: Mudassir Marwat

Microsoft's transition FAQ answers this under its own heading, on a page revised in July 2026 — a retirement date for BYOD hasn't been determined, and Microsoft recommends transitioning in the same sentence. Both halves are the answer. Here are the five Microsoft pages checked, the four dates Microsoft documents for Export to Data Lake, why any single-date summary of it is wrong, and why a bounded no is still not a reason to stay.

Mudassir Marwat
8 min read
ERP Write-Back & Integration
Read Article
Trending
116%

Why do your data events never fire for some entities?

Same topic cluster: ERP Write-Back & Integration
Same author: Mudassir Marwat

Microsoft names the class exactly - when a data entity uses a view as its primary data source, data events don't trigger. Not all views, not all entities - the entity's primary data source. This article gives Microsoft's wording and its stated reasons, the separate temporary-table case that raises an error instead of staying silent, and the published throughput figures that Microsoft says the environment does not explicitly throttle.

Mudassir Marwat
8 min read
ERP Write-Back & Integration
Read Article
Trending
116%

What does dual-write actually cost you in transaction budget?

Same topic cluster: ERP Write-Back & Integration
Same author: Mudassir Marwat

A budget with three published lines. Microsoft states a two-minute transaction time limit that includes the time to process standard and custom Dataverse plugins, a ceiling of 1,000 records per single transaction in the finance and operations to Dataverse direction, and a plan of record restricting dual-write to a one-to-one mapping. Every dual-write write spends from all three, and the bill arrives at posting time.

Mudassir Marwat
8 min read
ERP Write-Back & Integration
Read Article
Trending
116%

What can't Dynamics 365 do natively for EDI?

Same topic cluster: ERP Write-Back & Integration
Same author: Mudassir Marwat

Finance and Operations publishes a substantial electronic-document capability — a configurable format engine, an electronic invoicing service, inbound and outbound ASN objects, and file-based integration with transformation. What none of those pages documents is the EDI layer itself: encode and decode, trading partners and agreements, envelope control numbers, acknowledgements and the transports. Microsoft documents those, in Azure. This is the scoping brief, with the pages searched named against each gap.

Mudassir Marwat
10 min read
ERP Write-Back & Integration
Read Article

Smart Recommendations

Our AI analyzes topic clusters, author expertise, and content relationships to surface the most relevant articles for you.

Topic Matching
Author Expertise
Content Quality
Personal Interests

Questions on this?

Talk to an engineer

Schedule a call