Data modeling for high-volume hiring workloads
Cloud & DevOps · Jan 2026 · 8 min read
Recruitment traffic is spiky, write-heavy, and read through dashboards. Three modeling choices kept assessment platforms responsive on campaign day.
Hiring platforms have an unusual traffic shape. Applications arrive in bursts tied to a campaign going live — tens of thousands in an hour, then near silence — and the same rows are then read repeatedly by recruiters filtering dashboards for weeks afterwards.
Separate the write path from the reporting path
That asymmetry is the entire design. The write path should be narrow and close to append-only: validate, insert, publish an event, return. Anything a dashboard needs that is not a raw field gets derived asynchronously by a consumer, not computed at request time.
The fastest query is the one you never run during a request.
Precompute the counters
Every recruitment dashboard wants counts by stage, by role, by source. Running those as aggregate queries on campaign day is how you take the platform down. We maintain counter rows updated by the same event consumers that process applications, and reconcile nightly against the source of truth.
-- before: 2.8s on campaign day, table-scanning
SELECT stage, COUNT(*) FROM applications
WHERE campaign_id = ? GROUP BY stage;
-- after: 3ms, one row per campaign+stage
SELECT stage, n FROM campaign_stage_counts
WHERE campaign_id = ?;
Cursor pagination, not OFFSET
Recruiters page deep into filtered lists. OFFSET 40000 asks the database to find and discard forty thousand rows before returning twenty, and it gets linearly worse the further they scroll. A keyset cursor over a sorted composite index stays flat regardless of depth, and it does not skip or duplicate rows when new applications arrive mid-session.
- Composite index matching the exact sort order the UI offers — and only the orders it offers.
- Encode the cursor as an opaque token so the client cannot invent positions.
- Cap page size server-side; a well-meaning integration will ask for ten thousand.
None of this is clever. It is the same three moves on every high-write, dashboard-read system I have worked on, and they consistently do more for perceived speed than any instance-size change.
Takeaways
- Keep the write path narrow and derive reporting data asynchronously.
- Precompute counters; never COUNT(*) a campaign-day dashboard.
- Keyset cursors over composite indexes stay flat where OFFSET degrades.
All notes · Shehzad Aslam