Run the three strategies yourself. Same data, same result set, same page — only the query shape differs.
loading…
This is an independent reproduction, not your cluster. The dataset is synthetic, but the
constraint is modelled faithfully: your ~30 GB on an M20's 4 GB of RAM is roughly a
7:1 data-to-cache ratio, reproduced here as ~1.3 GB against a 0.25 GB WiredTiger cache.
Every query below is capped — a timeout is the result.
1 · The listing endpoint
Set a page and run all three. Then try page 500 and watch which ones survive.
A · Current implementation
$lookup → $unwind → $match → $sort → $skip
not run yet
B · Reverse the join
customers first → $in → $skip
not run yet
C · Denormalised + ESR + keyset
one compound index, range cursor
not run yet
2 · The search box
An unanchored /term/ cannot use an index. Search for something rare — the
scan must read every document before it can say "no results".
Unanchored /term/
COLLSCAN — every document read
not run yet
Anchored /^term/ + index
IXSCAN — b-tree range seek
not run yet
examined per returned is the number that matters: documents the server read for every
document you received. When it runs to thousands, cache thrashes, CPU spikes, and a stalled
primary is what triggers a replica-set election. Fixing that is cheaper than a tier upgrade.