La paginación es una decisión de rendimiento
Devolver todas las filas está bien hasta que deja de estarlo, y el punto en que deja de estarlo llega sin aviso. El tiempo de respuesta sube poco a poco, el tamaño de la respuesta sube poco a poco, y un día una lista que cargaba al instante tarda cuatro segundos porque la tabla de detrás creció.
El Capítulo 5 paginó la lista de consumidores y acotó per_page por los dos lados. Ese límite es un control de rendimiento tanto como de seguridad: el tamaño de página decide cuánto trabajo puede pedir una petición.
Hay un costo que conviene conocer. paginate() ejecuta un COUNT(*) junto a la consulta de la página para saber el total, y en una tabla grande ese recuento es trabajo de verdad. Si tus consumidores solo piden «la página siguiente», cursorPaginate() se salta el recuento y sigue siendo rápido por muy profundo que lleguen. La respuesta no tiene entonces total, y ese es el precio que se paga. (Documentación de Laravel: Database: Pagination › Cursor Pagination.)
Los índices y las consultas que los necesitan
Un índice ayuda solo a la consulta para la que se construyó. Añade uno por si acaso y habrás pagado un costo de escritura en cada inserción y cada actualización a cambio de nada.
Ese mismo servicio de dominios cuenta los dominios activos de un sitio en cada intento de compra, un camino muy transitado:
Domain::query()
->where('site_id', $site->id)
->whereNotIn('status', $inactive)
->count();
La migración que creó la tabla lleva el índice para exactamente esa consulta, porque las dos se escribieron juntas:
$table->index(['site_id', 'status']);
Es un índice compuesto, no dos separados, y el orden de las columnas importa. Este índice sirve a WHERE site_id = ? solo y a WHERE site_id = ? AND status = ? juntos, porque ambos usan sus columnas de la izquierda en orden. No ayudaría a una consulta que filtrara solo por status.
Mira primero la consulta, y diseña después el índice a su medida. Un índice añadido porque «es una clave foránea, seguramente lo necesita» tiene el mismo problema que una caché sin medir: no sabes si está haciendo algo hasta que lo compruebas.
El tamaño de la respuesta también es latencia
Una consulta lenta es un problema de rendimiento obvio. Una respuesta grande es uno menos obvio, pero cada byte tiene que transmitirse, recibirse e interpretarse antes de que tu consumidor pueda actuar.
La compresión, que el Capítulo 6 dejó en manos del servidor web, arregla los bytes que ya estás enviando. No arregla el envío de bytes que no hacía falta enviar. Si un Resource incluye campos que ningún consumidor lee, esa es carga que serializas, comprimes y transmites para nada. El arreglo es disciplina en el Resource: devuelve lo que el consumidor usa, no todo lo que el objeto resulta tener.