Eager Loading con Laravel Eloquent

Laravel Migration: Guía Paso a Paso y Opciones Avanzadas

Te puede interesar: Cómo instalar Laravel en XAMPP

¿Qué es la carga rápida o Eager loading?

Eager loading es un concepto en el que cuando se recuperan elementos, se obtienen todos los elementos necesarios junto con todos (o la mayoría) los elementos relacionados al mismo tiempo. Esto contrasta con la carga lenta o lazy loading, en la que sólo se obtiene un elemento a la vez y se recuperan los elementos relacionados sólo cuando se necesitan.

¿Qué es eager loading?

Para ponerlo en una perspectiva más de base de datos 😉 digamos que tienes una base de datos que contiene dos tablas – preguntas, y opciones. Todas las opciones están relacionadas con las preguntas a través de la columna question_id en ellas, y por supuesto, una pregunta tiene múltiples opciones. Necesitamos recuperar nuestras preguntas de la base de datos para que se muestren en la vista. Hay dos maneras de hacerlo:

Forma 1: Obtenemos las preguntas, empezamos a hacer un bucle a través de ellas, y para cada pregunta, vamos a la base de datos para recuperar las opciones relacionadas. *Esto es una carga perezosa, es decir, retrasamos la recuperación de las opciones hasta que las necesitemos.

Forma 2: Directamente desde la base de datos, obtenemos las preguntas y recuperamos las opciones asociadas. De este modo, al mostrar las preguntas, no hacemos viajes separados a la base de datos para obtener las opciones, sino que mostramos las opciones que ya existen en las preguntas. Y esto, es Eager loading.

Trabajemos el Eager loading con Laravel

A partir de este punto del artículo, hablaré en términos más parecidos a los de Laravel, pero manteniendo la idea lo más genérica posible, así que ¡vamos allá!

El Eager loading nos ayuda a resolver el problema de la consulta N+1. Veamos una ilustración sencilla utilizando nuestros datos de preguntas y opciones anteriores.

Supongamos que tenemos un modelo elocuente Question

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Question extends Model{
public function options(){
return $this->hasMany(Option::class);
}
}

Y un modelo Option :

<?php
namespace App'
use Illuminate\Database\Eloquent\Model;class Option extends Model{
public function question(){
return $this->belongsTo(Question::class);
}
}

Supongamos de nuevo que tenemos 20 registros en nuestra tabla de preguntas, para obtener todas las preguntas, todo lo que tenemos que hacer es

$questions = Question::all();

Entonces, para obtener todas las opciones asociadas a una pregunta, haríamos algo como

foreach ($questions as $question){
echo $question->option->count() . "<br>";
}

Esto es lo que ocurrirá con el escenario anterior:

La consulta se ejecutará una vez por primera vez para obtener las 20 preguntas, y luego 20 consultas más para obtener las opciones asociadas. En total son 21 consultas, es decir, 20(N) + 1

Eager Loading con Laravel Eloquent
N + 1

Eso es prácticamente una lazy loading.

Sin embargo, con el eager loading, para obtener las 20 preguntas y sus opciones, sólo necesitamos dos consultas, que se pueden lograr de la siguiente manera::

$questions = Question::with('options')->get();foreach ($questions as $question){
echo $question->option->count();
}

Al utilizar el método with hemos cargado simultáneamente las 20 preguntas junto con sus opciones. Para una mejor comprensión, la consulta SQL resultante tiene el siguiente aspecto:

select * from questions

select* from options where question_id IN (1, 2, 3, 4, 5 ... 20)

son los identificadores de las preguntas en cuestión.

Con el eager loading, hemos ahorrado los viajes de ida y vuelta de golpear la base de datos, que es realmente bueno para la salud de nuestra aplicación y el servidor.

Con laravel, podemos incluso hacer eager-load múltiples relaciones en una llamada.

Supongamos que tenemos otra relación en nuestro modelo de preguntas, por ejemplo Categoría

public function category(){
return $this->belongsTo(Category::class);
}

En una llamada, podemos obtener las preguntas, junto con las opciones asociadas y las categorías, y eso puede hacerse como:

$questions = Question::with(['options', 'category'])->get();

Sin que nuestro código tenga que golpear la base de datos varias veces, podemos acceder a las relaciones fácilmente

 foreach ($questions as $question){
echo "Category name is {$question->category->name} <br>";
foreach ($question->options as $option){
echo "Option is {$option->text} <br>";
}
}

Laravel todavía nos facilita la vida dándonos la posibilidad de hacer eager load de las relaciones anidadas, es decir, queremos hacer eager load de la relación que estamos cargando. Por ejemplo, suponiendo que la relación de categoría de nuestras preguntas está relacionada con un autor, podemos obtener las preguntas junto con la categoría relacionada (y luego el autor haciendo lo siguiente):

$questions = Question::with('category.author')->get();

Aquí hay un enlace a la documentación de laravel sobre eager loading

Algunas notas personales:

Aunque el eager loading parece algo muy bonito, no siempre es una solución para todos los casos.

Algunas ventajas y desventajas de el eager loading:

Pros

  • Obtienes todo lo que necesitas de una vez
  • No hay retraso en el acceso a los datos durante su uso por parte de los usuarios
  • Menos consultas para impactar en la base de datos

Contras

  • Podrías estar recibiendo datos que no necesitas realmente
  • La consulta inicial es lenta, y podría ser mala para los casos en los que hay que obtener muchos registros de una sola vez.
  • Por supuesto, utiliza más memoria.

En resumen, la carga ansiosa es un patrón que brilla mucho cuando se utiliza correctamente.

Eso es todo por mi parte, espero que disfruteis del artículo.