Cuando trabajamos en nuestros proyectos es posible que nos preguntemos si estamos desarrollando una aplicación que trabaja de forma correcta con la base de datos, si la estamos colapsando o quizás nos hacemos la pregunta ¿Existe una mejor forma de hacerlo?. En este artículo vamos entender cómo funcionan los patrones Eager Loading y Lazy Loading, cuándo debemos usar cada uno y finalmente vamos a observar un pequeño ejemplo.

Eager Loading

El patrón de diseño Eager Loading (en español podríamos traducirlo como Carga Apresurada) consiste en la asociación de modelos relacionados para un determinado conjunto de resultados con solo la ejecución de una consulta, en lugar de tener que ejecutar N consultas, donde N es el número de elementos en el conjunto inicial.

¿Cuando debemos usar Eager Loading?

  1. En «un lado» de las relaciones de uno a muchos y si estás seguro que se usará en todas partes con la entidad principal. Por ejemplo, el usuario de un artículo o la categoría de un producto.
  2. Cuando las relaciones no son demasiadas, ya que es una buena práctica utilizar Eager Loading para reducir las consultas en el servidor.

Lazy Loading

El patrón de diseño Lazy Loading (en español Carga Diferida) consiste en retrasar la carga o inicialización de un objeto hasta el mismo momento de su requerimiento. Esto contribuye a la eficiencia de los programas, evitando la precarga de datos que podrían no llegar a utilizarse.

¿Cuando debemos usar Lazy Loading?

  1. Frecuentemente es usado en el «lado de la colección» de las relaciones de uno a muchos, como artículos de un usuario o productos de una categoría.
  2. Cuando sabes exactamente que no necesitarás una propiedad al instante, con esta acción evitas una consulta más larga y solo solicitas los datos de la relación cuando sean necesarios.

Ejemplo (Basado en Laravel)

Cuando se está trabajando con Laravel y su ORM Eloquent podemos observar un ejemplo de uso muy común de la Carga Diferida o Lazy Loading cuando hacemos algo parecido a esto:

$tickets = App\Ticket::all();

// Dentro de un foreach en nuestra vista:
@forach ($tickets as $ticket)
    {{ $ticket->user->name }}
@endforeach

El código anterior muestra un problema que podemos encontrarnos frecuentemente ya que un Ticket tiene un User. La propiedad user  es el nombre del método que guarda la relación desde el modelo Ticket hasta el modelo User. El detalle es que cuando queremos acceder a dicha propiedad estamos realizando una consulta a la base de datos, esto quiere decir que si tenemos 30 tickets vamos a tener 30 consultas más la consulta donde obtenemos todos los tickets.

Las consultas a la base de datos serían como estas:

select * from `tickets`

select * from `users` where `users`.`id` = '3' limit 1

select * from `users` where `users`.`id` = '1' limit 1

select * from `users` where `users`.`id` = '2' limit 1

select * from `users` where `users`.`id` = '2' limit 1

La primera consulta es donde obtenemos todos los tickets el resto se muestran 4 de las 30 consultas que tenemos en este ejemplo.

¿Es un problema?

Definitivamente sí, ya para este caso la información del usuario es una sola porque se trata de una relación one-to-many o uno a muchos y si los datos del usuario son imprescindibles en un Ticket  , sería una buena práctica cambiar tantas consultas a la base de datos por tan solo 2.

Este problema es llamado como «El Problema de N+1» el cual se da al querer acceder a un objeto y sus N objetos relacionados. Esto implica hacer una consulta para obtener el objeto principal y las claves de los objetos relacionados.

Solución

Para cambiar las 30 posibles consultas o más por solo 2 podemos utilizar el método with de Eloquent, el cual es un método donde podemos definir cuál relación vamos a cargar por cada Ticket.

Para utilizar el método with debes asegurarte que las relaciones deben estar bien definidas en tus modelos y apuntando de forma correcta a las llaves foráneas.

Este es un principio de Eager Loading. De esta forma podemos utilizar el método antes mencionado:

$tickets = App\Ticket::with('user')->get();

Una de las ventajas de Laravel es que podemos saber lo que está pasando con solo leer su sintaxis expresiva, necesitamos obtener todos los tickets con sus usuarios. Ahora, las consultas que estamos haciendo a la base de datos son las siguientes:

select * from `tickets`

select * from `users` where `users`.`id` in ('1', '2', '3')

Tenemos ahora tan solo 2 consultas, la primera ya la hemos visto pero la segunda consulta se trata de obtener todos los usuarios que se encuentren entre un rango de id.

Si trabajas con Laravel y deseas verificar el número de consultas que haces en una petición de tu aplicación puedes  integrar una barra de depuración como Laravel Debugbar. o verlas con Clockwork, una herramienta para depurar tus aplicaciones de PHP y Laravel

No todo es color de rosa…

En el ejemplo anterior, hemos reducido el número de consultas, pero hemos creado una consulta un poco más larga; la cual en términos de rendimiento puede ser mejor. Aunque, si tenemos muchos más usuarios la consulta se puede complicar un poco y ser algo pesada. Esto quiere decir que en ocasiones hacer pequeñas consultas puede ser más factible a realizar una sola pero muy grande.

Por otro lado, en el ejemplo no hemos colocado algún tipo de condición para mostrar los detalles del usuario propietario de cada ticket, pero en tu sistema puede existir una condición como la de ocultar la información del usuario y solo mostrarla cuando sea el propietario. Es en ese momento cuando te puedes preguntar: ¿Es factible obtener todos los usuarios de cada uno sin importar que pase con mi condición?.

Con esto me despido, espero que tengas una idea clara de que significa cada uno de estos patrones. Es importante destacar que ninguno es mejor que otro, sino que dependiendo de la ocasión, debemos tomar la decisión de cuál debemos utilizar.

Si te ha gustado este articulo por favor compártelo en tus redes sociales. No olvides seguirnos en Twitter y suscribirte a nuestro boletín:

Suscríbete a nuestro boletín

Te enviaremos publicaciones con consejos útiles y múltiples recursos para que sigas aprendiendo.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.