Case Dashboard: Fourteen Seconds to First Paint
A Case Dashboard shows an a!gridField of 200 cases. For each row, the developer uses a!forEach to build columns that call a!queryRecordType on the User record type to fetch the assignee's display name and photo, plus a count of open sub-tasks. First paint takes 14 seconds. Twelve rows show a blank assignee. The grid page size is 25, but the developer proposes raising it to 200 'so all the queries happen once'. User records sync from LDAP nightly; the twelve blank assignees are contractors created after the last sync.
1. Identify the performance anti-pattern and describe the interface structure you would use instead.
Read the worked answer
The anti-pattern is querying inside the row-rendering path. Every visible row runs its own record query for the user and another for the sub-task count, so a 25-row page issues roughly 50 queries, and the grid re-evaluates those cells on refresh. It is the N+1 pattern wearing a SAIL costume: the cost is driven by row count, not by the data the user asked for.
Structure I would use:
- One query for the page of cases (with
a!pagingInfo), so the grid is backed by a single data source. - One query for the distinct assignee IDs on that page (an
INfilter), and one aggregate query for the sub-task counts grouped by case ID. - Build the lookups once in
a!localVariablesas maps (id -> name, id -> photo, id -> count). - Render cells with
index(map, ri.assigneeId, null)- pure in-memory lookups, no queries in the cell.
That turns a page load into three queries regardless of page size. It also keeps the logic readable: the data-fetching is one block, the rendering is another.
If the dashboard is read-heavy and the counts tolerate slight staleness, materializing the count on the case record removes the second aggregate entirely - same trade-off as any precomputed field.
2. Why are twelve assignees blank, and how do you fix both the symptom and the cause?
Read the worked answer
Symptom: the query returns an empty result for those twelve users because the contractor records do not exist in the User record type yet - they were created after the nightly LDAP sync. When code calls first() or index(list, 1) on an empty result, it either errors in that cell or renders nothing, which is what the user sees.
Fix the rendering safely. Use index(list, 1, null) (or an a!isNullOrEmpty guard) and render an explicit fallback - the assignee ID or 'Not yet synced' - rather than a blank cell. A blank is indistinguishable from 'unassigned', which is a data-quality conclusion the user will draw and act on incorrectly.
Fix the cause. Either trigger a sync when the user is created (a sync step in the onboarding process), or run an on-demand sync of the affected records before the dashboard loads, or include contractors in the LDAP feed so the nightly job covers them. Widening the query does not help: the record genuinely is not there, and no amount of interface work will make it appear.
Also worth checking whether the blanks correlate with a process that creates contractor accounts outside business hours - that would explain why the dashboard looks fine in the afternoon and broken in the morning.
3. Evaluate the proposal to raise the page size to 200.
Read the worked answer
It makes the problem worse, and it makes it worse in the least visible way.
The proposal assumes the queries run once regardless of page size. They do not: the queries are per row, so 200 rows means roughly 400 record queries in a single request instead of about 50. Load time grows, memory grows, and the request is more likely to hit evaluation limits and fail outright rather than merely be slow. If the queries were batched (as described earlier), page size would stop mattering to query count - but then there would be no reason to raise it either.
A second cost is usability: a 200-row grid defeats the purpose of paging. Users scroll, lose their place, and re-sort, and each of those interactions re-evaluates the grid.
Keep paging at a sensible size and fix the access pattern instead. If users genuinely need to see more rows at once, the right answer is a report or export, not a bigger grid. And confirm the 14 seconds is actually query time before optimizing anything - a chart, a logo image, or a large photo field in the grid can dominate first paint just as easily as a query.