Simor Soft case study · ERP performance

Case study: improving large ERP table performance

A growing operational table had become expensive to load, search, sort, and use. Simor Soft treated the delay as an end-to-end data problem rather than a cosmetic grid problem, then improved the path from query to browser without weakening accuracy, permissions, or control.

Published August 18, 2026 · In-depth engineering case study

Case study at a glance

Large operational datasets are difficult because the visible grid is only the final layer. Database access, joins, calculated fields, authorization, serialization, transfer, browser rendering, filters, and exports all contribute to perceived speed. Optimizing one layer without evidence can simply move the bottleneck.

The resulting design returned a bounded and relevant result set, preserved reliable sorting and filtering, and kept totals aligned with authoritative ERP records. The work also established a repeatable measurement method for future screens instead of relying on subjective impressions.

Evidence boundary: This case study describes real Simor Soft engineering experience. Client-identifying details and confidential production data are excluded. No unsupported performance percentage or financial result is claimed.

Operational context and symptoms

The table supported daily ERP work rather than occasional reporting. Users needed to locate records, compare statuses, apply filters, move between result pages, and open details while the underlying history continued to grow. Delays interrupted a workflow built around quick repetition, so a screen that eventually completed could still reduce productivity and confidence.

The phrase slow table was too broad for diagnosis. Simor Soft separated initial response time, database duration, transferred bytes, row count, render work, interaction delay, export behaviour, and concurrent activity. This prevented a visual adjustment from being mistaken for a durable correction and gave the team a shared vocabulary for comparing changes.

Measure before changing the implementation

Representative scenarios used realistic volume, common filters, difficult combinations, late pages, broad date ranges, and restricted roles. Measurements followed the request from service boundary through query execution and client rendering. Query plans and repeated calls were reviewed beside payload size so the actual cost was visible.

A development dataset can hide cardinality, join, and permission problems. The team therefore compared like-for-like scenarios and recorded normal and boundary conditions before choosing indexing, query changes, caching, pagination, or rendering work. Every proposed optimization needed a baseline and an observable result.

Move operations to the correct layer

Sorting, filtering, and paging moved to the server wherever the full dataset was not safely present in the browser. The API accepted a bounded page size, stable order, validated criteria, and continuation boundary. It returned fields required by the current view instead of serializing full entities for every row.

Client-side operations on a partial set can display misleading counts or omit qualifying records, while loading everything defeats paging. Keeping operations close to the governed source allowed the same rules, permissions, and status definitions to control both visible rows and result totals.

Design stable pagination and search

Pagination required deterministic ordering. Sort fields used a unique tie-breaker so records with equal dates or statuses did not jump between pages. For deep navigation, the design considered continuation-based access rather than repeatedly asking the database to skip an expanding number of rows. Search was constrained to meaningful fields.

Filters became an explicit contract rather than arbitrary query fragments. Allowed operators, types, date boundaries, null behaviour, and maximum ranges were defined. This improved safety and testability and let the interface explain when an expensive broad request needed refinement.

Reduce database and payload cost

The team checked whether indexes matched actual filters and sort patterns, whether joins multiplied rows, and whether calculations repeated unnecessarily. Only evidence-supported indexes were introduced because indexes also affect writes and storage. List projection was narrow; detailed data loaded when a record was opened.

Repeated reference data was not embedded wastefully in every row. Caching was limited to information with an understood freshness and invalidation path. Compression reduced transfer cost but was never used as justification for an oversized response. Current transactional values continued to come from an authoritative request.

Keep rendering responsive and accessible

A faster service can still produce a sluggish screen if the browser creates too many elements or performs work after each keystroke. The grid used bounded rows, deliberate column rendering, appropriate input delay, and clear loading and empty states. Layout remained useful at desktop, tablet, and mobile widths.

Users retained criteria when returning from detail, could identify active filters, and received an understandable no-results state. Keyboard use, focus order, headings, and accessible labels were verified so the performance correction did not create a faster interface that became harder for people or automated agents to navigate.

Validate correctness under change

The optimized result was reconciled against known transactions and the previous authoritative output. Tests covered first and last pages, equal sort values, inserts, removals, null fields, date edges, filtered totals, role restrictions, and concurrent updates. Export and screen results used the same filter definition.

Regression testing extended beyond speed. The team verified server-side permissions, record links, totals, and safe error responses. Production observability captured slow requests and failures, allowing support to distinguish a data-specific exception from a general regression.

Outcome and reusable lesson

The durable outcome was a clearer boundary between list and detail workloads, a smaller data contract, and a repeatable measurement process. Users could work with relevant records without waiting for complete history to reach the browser, while business rules and ownership remained intact.

A large table is a system, not a widget. Effective improvement joins database design, API behaviour, authorization, transfer efficiency, rendering, usability, and monitoring. The same pattern can support purchasing, inventory, sales, audit, and finance screens, but each must be validated against its own workload.

Why common fixes did not address the whole delay

Increasing the grid page size would have hidden navigation while increasing transfer and rendering cost. Loading the full history into the browser would have weakened freshness, memory use, permission enforcement, and mobile behaviour. Adding indexes without reading the query plan risked faster reads for one filter and slower writes everywhere else. Caching an operational result without a reliable invalidation rule could have made a fast answer incorrect.

The team also avoided treating a warm developer-machine request as proof. The useful baseline included realistic row distribution, difficult filters, authorization, serialization, network transfer, browser work, and concurrent activity. Measurements separated typical behaviour from slow-tail cases.

The release compared correctness before speed

The optimized path ran against known transaction sets and representative roles. The team compared row identity, filtered totals, first and last pages, null values, equal sort values, date boundaries, inserted records, deleted records, and export results. A unique tie-breaker protected stable ordering when business fields were equal.

Release monitoring separated database duration, endpoint duration, payload size, error rate, browser responsiveness, and the filters associated with a slow request. Rollback conditions were agreed before production. This made it possible to detect whether a later feature expanded the projection, removed a bound, or introduced repeated lookups.

What the team retained for future support

The final handoff documented the list contract, allowed filters, paging rule, ordering, required indexes, performance scenarios, known limits, dashboards, and regression tests. Support could distinguish a generally slow endpoint from one data-specific plan or unusually broad request. Another engineer could reproduce the measurements without reverse-engineering an opaque optimization.

The reusable lesson is investigative: measure the entire route, place work at the correct layer, and reconcile the result. It is not a claim that every slow ERP table needs the same index, cache, grid, or pagination technique.

Large ERP table performance review checklist

  • Record row volume, data distribution, common filters, late pages, and concurrent use.
  • Separate query, authorization, serialization, transfer, and render duration.
  • Keep filtering, sorting, and paging authoritative on the server.
  • Return list fields separately from detailed record data.
  • Use deterministic ordering and validate every filter contract.
  • Reconcile optimized rows, totals, permissions, and exports.
  • Monitor slow tails and protect the improvement with regression scenarios.

How Simor Soft applies this ERP performance experience

Simor Soft can review a slow purchasing, inventory, sales, audit, accounting, or manufacturing table using representative data and the actual roles that depend on it. The engineering review follows evidence from the database to the API and browser, while QA verifies data integrity, authorization, responsive behaviour, and recovery conditions.

The objective is a supportable improvement that preserves the meaning of the ERP record. Simor Soft can adapt the table contract, queries, indexes, API, filters, exports, and interface where evidence supports the change, then retain the measurement and test assets for future releases.

Performance budgets followed representative user actions

The team did not set one arbitrary time for every request. Opening the initial list, applying a common filter, reaching a late page, changing sort order, exporting a governed result, and opening record detail have different costs and user expectations. Each scenario received a repeatable dataset, role, filter, measured boundary, and failure threshold.

Budgets were reviewed as volume and usage changed. A request that remained within its limit could still require investigation when payload size, query reads, or slow-tail frequency rose steadily. This early evidence made regression visible before the table returned to the original operational problem.

Threshold alerts therefore used both duration and workload indicators, with enough request context to reproduce the affected scenario safely.

Related Simor Soft ERP case studies

Apply the experience

Discuss your ERP engineering challenge with Simor Soft

Bring the workflow, representative data, exceptions, integrations, and expected outcome.