Acumatica · Gi

Acumatica GI Server-Side Filtering — Best Practices

Acumatica GI Server-Side Filtering — Best Practices sits at the intersection of three forces: what the user wants to see, what the database can deliver, and what the platform will.

John Kihiu12 min read

The single most common performance defect I find in inherited Generic Inquiries is a filter that looks like it restricts the query but actually runs after the data has already been fetched — client-side, in the browser's grid, rather than as a SQL WHERE clause on the server. It behaves identically to the user in a small dataset and catastrophically differently once the underlying table has real volume.

Conditions tab versus the grid's quick filter — not the same thing

Acumatica gives you two ways to narrow a GI's visible rows, and only one of them pushes down to the database:

Verify with the request profiler, not by eyeballing results

The only reliable way to confirm a filter is actually running server-side is to check the SQL text via the Request Profiler (SM205070) or equivalent tracing and see your filter value inside the WHERE clause. A filter that "looks like it works" because the grid displays the right rows can still be doing the narrowing client-side on data that was expensively fetched in full first.

Every parameter needs a matching Conditions-tab entry to actually filter anything

A parameter declared on the Parameters tab does nothing on its own — it is just a typed input with a default. It only becomes a filter once referenced inside a Conditions-tab entry with =[@ParamName]. I have inherited more than one GI where a parameter exists, looks configurable, and is entirely decorative because nothing on the Conditions tab actually references it — the GI always returns the full table, and the parameter is a UI element with no effect.

PARAMETER WITH NO EFFECT VS WIRED CORRECTLY
-- Broken: parameter exists, nothing references it. Filter is decorative.
Parameters tab:   @FromDate  (declared, has a default)
Conditions tab:   (empty — no condition uses @FromDate)

-- Correct: parameter is actually wired into a SQL-pushed condition
Parameters tab:   @FromDate  (declared, has a default)
Conditions tab:   ARInvoice.DocDate  Greater or Equal  =[@FromDate]

Filters that technically run server-side but still block indexes

Pushing a filter into the Conditions tab is necessary but not sufficient for real performance — a condition that wraps the indexed field itself in a function (a date-truncation, a string manipulation) can prevent the database from using an index on that column even though the WHERE clause is genuinely server-side. Prefer conditions that compare the raw field directly against a parameter or literal, and do any transformation on the parameter/literal side instead:

SARGABLE VS NOT
-- Can use an index on DocDate
ARInvoice.DocDate  Greater or Equal  =[@FromDate]

-- Cannot use an index — function wraps the column
Year(ARInvoice.DocDate)  Equals  2026

Filter before you join where the relationship allows it

Where a condition can be expressed on the primary table before a join fans rows out (see the cross-table-joins piece), filtering early reduces both the join's work and the eventual row count — the query planner often handles this automatically, but explicit, correctly-typed conditions give it the best chance to.

Wrapping up

Real server-side filtering means a Conditions-tab entry that is actually referenced by a parameter, compiles into the SQL WHERE clause, and avoids wrapping the filtered column in a function. Verify with the request profiler rather than trusting that a filter "looks like it's working" — grid-level filtering on an already-fetched page will fool you every time until the table grows.

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.