Acumatica · Reports

Acumatica Report Designer — Performance Tuning

How to make Acumatica Report Designer reports run in seconds instead of minutes — schema-level filtering, aggregation in SQL, indexed joins, and the three things that fix 90% of slow reports.

John Kihiu12 min read

"The invoice prints fine, but the month-end register takes eleven minutes" is a message I get from Acumatica clients often enough that I have a standard diagnostic sequence for it. Report Designer reports are usually slow for boring, fixable reasons — the schema pulls too much, filters run on the wrong side, or a subreport turned the render into an N+1 storm. Here is the sequence, in the order that finds the problem fastest.

Step 0: measure before touching anything

Run the report from the browser with the Request Profiler enabled (SM205070). You care about two numbers: total SQL time versus total request time, and the count of SQL queries. The split tells you which world you are debugging:

Push filters into the schema, not the layout

The single most common defect I find: the report's schema selects a broad dataset and then the layout suppresses rows with visibility expressions, or groups filter with expressions like =IIf([ARInvoice.DocDate] >= [@FromDate], ...). The database happily returns every invoice since go-live; the report engine then throws most of them away in memory.

Every parameter should appear as a condition on the Filters tab of the Schema Builder so it becomes a SQL WHERE clause. Check this by profiling: the query text in the profiler should contain your date range. If it does not, the filter is running client-side.

SCHEMA FILTER (RUNS IN SQL)
Field:      ARInvoice.DocDate    Condition: Greater or Equal   Value: =[@FromDate]
Field:      ARInvoice.DocDate    Condition: Less or Equal      Value: =[@ToDate]
Field:      ARInvoice.Released   Condition: Equal              Value: True

Trim relations and fields

The Schema Builder makes it painless to join eight tables and select every field "in case". Every joined table widens the row and can change the query plan; every selected long text field (descriptions, note text) inflates the data transferred. Two rules:

Also check for the fan-out trap: parent joined to two child tables multiplies rows, and your aggregates go wrong and your row count explodes. That is a case for a subreport or a pre-aggregated join, not a wider flat query.

Subreports: the N+1 you can see in the profiler

If the profiler shows one query repeated with different parameters hundreds of times, a subreport (or an embedded per-row report control) is executing per detail row. Fixes in order of cheapness: move the subreport from the detail band to a group footer; replace an aggregate-only subreport with a joined SQL aggregate; pre-flatten the child data into a PXProjection the parent schema can join once.

Aggregates in expressions do not push down

Layout-level aggregate functions — Sum(), Count() in group footers — are computed by the report engine over the fetched rows. That is fine. What is not fine is fetching detail rows only to compute a total you never display line-by-line. If the report shows totals without details, aggregate in the schema (GROUP BY via a projection or GI-backed source) and fetch the totals directly.

Database-side: indexes and the big history tables

When the profiler shows one slow query, take its text and look at the plan (on SaaS, work with Acumatica support; on private cloud, do it yourself). The usual suspects in my experience:

Rendering costs: images and page count

Two rendering-side offenders worth checking when SQL is fast but the report is not: high-resolution logos placed in the detail band (rendered per row — put them in the page header, and resize the source image to roughly its printed size), and reports that paginate into thousands of pages nobody will read. For the latter, question the requirement: a 4,000-page register exists to be exported, and a GI with Export to Excel serves that need in a tenth of the time, because it skips pagination entirely.

When it is still slow: schedule it

Some reports are legitimately heavy — a full-year consolidated pack is going to cost real compute. Move those to the Automation Schedules with output to email or a file share, run them off-hours, and keep interactive rendering for interactive-sized questions. Users perceive a report that arrives in their inbox at 6 a.m. as fast, regardless of how long it ran.

Wrapping up

Tune in this order: profile, push filters into SQL, trim joins and fields, kill per-row subreports, then and only then look at indexes. Ninety percent of slow .rpx reports I have been handed were fixed in the first three steps without touching the database. The profiler is your ground truth — never tune a report you have not measured.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.