The Complaint That Started It

The report from users was simple: ‘the submissions list is slow.’ Not broken — slow. The grid that shows a reviewer every submission they can access was taking around twelve seconds to render for users with substantial portfolios. Twelve seconds is an eternity in interface time. Users described opening the page, going to get coffee, and coming back.

Here is the thing about ‘slow but working’ bugs in enterprise software: they rarely get fixed, because they never page anyone. There is no error, no failed request, no red dashboard. Just a quiet tax on every user, every day, compounding into the impression that the system is heavy — and, eventually, into workarounds. We decided to treat twelve seconds as an incident, and what we found is the single most common performance defect in data-driven applications: the N+1 query.

What an N+1 Query Is

The pattern is almost always innocent in origin. You write code that fetches a list of records — one query, fast. Then, for each record, you need related information: its status, its latest activity, its associated counts. The natural way to write that is a loop: for each submission, look up its details.

The result: loading a list of N submissions issues one query for the list plus N queries for the details — hence N+1. With 10 rows, nobody notices. With hundreds of rows, the page issues hundreds of sequential database round-trips, each individually fast, collectively disastrous. The killer property of N+1 is that it scales with success: the more a customer uses your platform, the more data they accumulate, the slower it gets. Your best customers get your worst performance.

That is exactly what our instrumentation showed: the grid endpoint was issuing a separate lookup per submission row — per-row status resolution, per-row related-data fetches — hundreds of round-trips to assemble one screen.

The Fix: Set Thinking Instead of Row Thinking

The remedy is conceptually simple and always the same shape: replace per-row lookups with set-based ones.

  • Batch the related fetches. Instead of asking ‘what is the status of submission 1… of submission 2…’, ask once: ‘here are all the identifiers on this page — give me all their statuses.’ One round-trip instead of N.
  • Join where the database can do the work. Much of the per-row information could be assembled by the database in the original query, which is what databases are spectacularly good at.
  • Consolidate onto one data path. Part of our N came from the endpoint stitching data from older, redundant read paths that predated the platform’s unified data layer. Moving the whole read onto the single governed data layer both removed queries and removed a source of inconsistency — two queries answering the same question is an invitation for them to disagree.

Result: the same grid, the same data, in roughly 0.7 seconds — a 17x improvement, achieved not by caching or hardware but by asking the database the right number of questions.

Why Performance Is a Compliance Issue

It is tempting to file this under engineering hygiene, but in regulatory software the stakes are more specific.

  • Slow systems breed shadow systems. When the official grid takes twelve seconds, users export to a spreadsheet once and work from the spreadsheet all week. Now decisions are being made from a stale, uncontrolled copy — the exact failure mode document control and audit trails exist to prevent. Performance is the price of being the single source of truth.
  • Review thoroughness is time-boxed. A reviewer with an hour and a sluggish tool checks fewer things. Nobody writes ‘the software was slow’ in a deviation report, but friction quietly shapes how much verification actually happens.
  • Trust generalizes. Users who wait twelve seconds for a grid start doubting everything else — is the sync current? did my action save? Responsiveness is how software communicates reliability.

How to Spot N+1 as a Buyer

You do not need database access to detect this pattern during an evaluation — you need realistic data volume and a stopwatch:

  • Demand a demo at scale. Every product is fast with 15 records. Ask to see the main working grids with hundreds of submissions or thousands of documents — volumes a real program accumulates.
  • Look for linear degradation. If a list of 200 takes roughly ten times as long as a list of 20, you are almost certainly watching per-row queries execute.
  • Ask the uncomfortable question: ‘What is your slowest screen for your largest customer, and what did you last do about it?’ Teams that measure have an answer; teams that do not will improvise one.

What We Took Away

Three lessons made it into how we work:

  • Treat chronic slowness as a defect with a ticket, not ambient weather. It has a root cause; root causes get found when someone looks.
  • Test at customer-shaped scale. Our performance checks now run against datasets sized like our heaviest real portfolios, because that is where N+1 lives.
  • One data path. Every redundant read path we retired removed both queries and disagreement risk. Consolidation is a performance strategy and an integrity strategy at once.

Twelve seconds to 0.7 did not add a feature, and no release note made it sound exciting. But users noticed within a day — and the spreadsheet exports stopped. Sometimes the most important compliance feature you ship is a page that loads before anyone reaches for a workaround.

If you are evaluating regulatory platforms, bring your real data volumes to the conversation — we are happy to be benchmarked at scale. Talk to a regulatory expert and ask to see the big grids first.