Dataverse exposes two first-class query languages, and most teams pick whichever they learned first. That is the wrong default. The query you write determines whether your form loads in 200ms or 2 seconds.
When OData wins
The Web API is your default for client-side reads. It supports $select, $expand, $filter, server-side paging via @odata.nextLink, and returns JSON. For form-side scripting, embedded canvas apps, and any browser-origin call, OData is the cheaper choice because the gateway does not need to translate XML.
const r = await Xrm.WebApi.retrieveMultipleRecords(
"account",
"?$select=name,revenue&$filter=statecode eq 0&$top=50"
);
When FetchXML wins
FetchXML is the only way to get aggregates, link-entity to N:N intersect tables with attribute aliases, and saved Advanced Find views without rewriting them. If you need count, sum, groupby, or distinct across joins, FetchXML is the answer. It also wins for plugin server-side queries because IOrganizationService.RetrieveMultiple(new FetchExpression(...)) avoids the OData parser entirely.
The hidden cost: $expand chains
OData $expand looks elegant but materializes related rows in-memory before paging is applied. Three levels of $expand on a 5,000-row account list will time out. FetchXML link-entity with link-type="outer" lets you control join cardinality explicitly and respects the 5,000-row page boundary.
The 5,000 row trap
Both languages cap at 5,000 rows per page. OData gives you a continuation token; FetchXML uses paging-cookie. If your code does not handle paging, you are silently truncating results. Audit every RetrieveMultiple call for paging logic this week.
Decision rule
- Aggregates or grouped joins -> FetchXML.
- Browser-side reads on a single table -> OData.
- Plugin or service code -> FetchXML, always (skip the parser).
- Power Automate Dataverse connector -> FetchXML for filters that need
not insemantics, OData otherwise.
What to do this week
Open your slowest model-driven form, capture the network tab, and rewrite any $expand chain deeper than two levels as a FetchXML link-entity query inside a JS web resource. Measure the delta. The number will surprise you.