The problem
getLocationMapPoints had significantly worse p99 than getLocations under identical load in charge-points v0.3 load tests. Same endpoint family, assumed same defaults — but not the same behaviour.
Investigation checklist
- Verify data parity — paginate both endpoints and count unique UIDs before blaming query performance.
offset=0
while true; do
uids=$(curl -s -H "x-api-key: $KEY" "$URL?offset=$offset" | jq -r '.items[].uid // empty')
count=$(echo "$uids" | grep -c '[a-z0-9]' || true)
[[ $count -eq 0 ]] && break
echo "$uids" >> /tmp/uids.txt
offset=$((offset + count))
done
sort -u /tmp/uids.txt | wc -lFound 11 locations in getLocations missing from getLocationMapPoints — all had publish: false. Different filtering semantics by design, not a bug.
- Check endpoint defaults and limits — endpoints in the same family can have different defaults.
# locations → default 100, max 100 (400 if limit > 100)
# map-points → default 500, max 500 (400 if limit > 500)getLocationMapPoints was returning 5× more items per request than getLocations.
- Run a controlled experiment with matched page sizes — pin
limitto the same value across both before drawing any conclusions.
Four pairings at 20 RPS, 30s each (ev/page_size_test.js):
| Pairing | locations p99 | map-points p99 |
|---|---|---|
| Default (no params) | 1.44s | 1.79s |
Offset only ?offset=rand(0-20) | 864ms | 2.18s |
Limit only ?limit=100 | 900ms | 673ms |
Offset + limit ?offset=rand(0-20)&limit=100 | 953ms | 497ms |
Key findings
Page size was the entire problem. limit=100 alone dropped map-points p99 from 1.79s → 673ms (~2.7×). No query changes needed.
Warning
Offset without limit makes things worse — map-points still returns 500 items but now scans past extra rows first. Never add offset without also setting limit.
At equal page size, map-points is faster than locations. Map-points returns 4 fields per item vs locations’ 25+. Lighter payload wins at every percentile once page size is controlled.
Locations has no room to improve via page size — it already defaults to its max of 100. Its latency floor is payload weight per item.
The fix
Lower MAP_POINTS_MAX_LIMIT from 500 → 100 in voltnet-omni/pkg/configs/configs.go. No query layer changes needed.
See also
- k6-metrics-and-config — how to interpret k6 output and set up per-endpoint tagging
- k6-large-tests — running tests at scale