PROBLEMA N+1
El problema N+1 es uno de los anti-patrones de rendimiento más comunes en programación cuando se trabaja con bases de datos relacionales y consiste en realizar una consulta y luego recorrer el resultado de esa consulta para obtener más datos realizando n consultas (n sería el total de resultados de la primera consulta) en vez de poder hacerlo todo en 1 o 2 consultas bien hechas. Ejemplo clásico (en Laravel):// Se obtienen todos los posts la tabla Posts
$posts = Post::all(); // ← 1 consulta
foreach ($posts as $post) {
echo $post->user->name; // ← aquí se traliza UNA consulta POR CADA post
}
consulta → SELECT * FROM posts
50 consultas → SELECT * FROM users WHERE id = 7
SELECT * FROM users WHERE id = 3
SELECT * FROM users WHERE id = 15
... (una por cada post)
Una solución sería:
// Mal (N+1)
$posts = Post::all();
foreach ($posts as $post) { echo $post->user->name; }
// Bien (2 consultas)
$posts = Post::with('user')->get();
foreach ($posts as $post) { echo $post->user->name; } // ← ya está precargado, 0 consultas extra
SOLUCIONES
| Solución | Laravel/Eloquent ejemplo | Cuándo usarla | Consultas finales |
|---|---|---|---|
| Eager Loading | Post::with('user')->get() | Casi siempre (la más común y limpia) | 2 (posts + users) |
| Eager Loading múltiple | Post::with('user', 'comments', 'tags')->get() | Cuando necesitas varias relaciones | 4 consultas |
| Lazy Eager Loading | $posts = Post::get(); $posts->load('user'); | Cuando decides después si cargar o no | 2 |
| Joins manuales | Post::join('users', ...)->select(...)->get() | Casos muy específicos o rendimiento extremo | 1 |
| select() + pluck() | Para listas simples sin objetos completos | Listas desplegables, reportes | 1 |