Returning every row is fine until it isn’t, and the point where it stops being fine arrives without warning. Response time creeps up, payload size creeps up, and one day a list that used to load instantly takes four seconds because the table behind it grew.
Chapter 5 paginated the consumers list and bounded per_page on both sides. That bound is a performance control as much as a safety one: the page size decides how much work one request can ask for.
One cost is worth knowing. paginate() runs a COUNT(*) beside the page query to learn the total, and on a large table that count is real work. If your consumers only ever ask for “the next page,” cursorPaginate() skips the count and stays fast however deep they go. The response then has no total, which is the trade. (Laravel documentation: Database: Pagination › Cursor Pagination.)
Indexes and the Queries That Need Them
An index helps only the query it was built for. Add one speculatively and you have paid write overhead on every insert and update for nothing.
That same domain service counts a site’s active domains on every purchase attempt, a hot path:
Domain::query()
->where('site_id', $site->id)
->whereNotIn('status', $inactive)
->count();
The migration that created the table carries the index for exactly that query, because the two were written together:
$table->index(['site_id', 'status']);
It is one composite index, not two separate ones, and the column order matters. This index serves WHERE site_id = ? alone and WHERE site_id = ? AND status = ? together, because both use its leftmost columns in order. It would not help a query that filters on status alone.
Look at the query first, then design the index to match it. An index added because “it’s a foreign key, it probably needs one” has the same problem as an unmeasured cache: you don’t know whether it is doing anything until you check.
Payload Size Is Latency Too
A slow query is an obvious performance problem. A large response is a less obvious one, but every byte has to be transmitted, received, and parsed before your consumer can act on it.
Compression, which Chapter 6 left to the web server, fixes the bytes you are already sending. It doesn’t fix sending bytes you didn’t need to send. If a Resource includes fields no consumer reads, that is payload you serialize, compress, and transmit for nothing. The fix is discipline in the Resource: return what the consumer uses, not everything the object happens to have.