Optimización de consultas SQL

Otra manera de optimizar nuestras consultas es utilizar la característica de paginación de Eloquent para evitar seleccionar todos los datos, y por el contrario obtenerlos en rangos de 15, 20, 50 o 100 resultados por página. En esta lección veremos cómo paginar datos con Laravel y los detalles que debemos tener en cuenta sobre las 2 formas de paginación que nos ofrece el framework.

Esta lección incluye un video premium

Regístrate para ver este video y cientos de lecciones exclusivas.

Mira el código en GitHub: actual, resultado, comparación.

Al utilizar el método all o llamar al método get sin especificar ningún tipo de restricción (por ejemplo, a través de where para agregar una condición a la consulta) obtendremos todos los resultados. Esto es viable únicamente si estamos 100% seguros de que la tabla contendrá pocos registros. Pero si tenemos 1000 productos deberíamos aplicar algún tipo de restricción o paginación de los resultados.

Paginación con Eloquent

Paginar con el ORM Eloquent es sumamente sencillo, cambia el llamado a get por el método paginate:

<?php
// routes/web.php

$products = Product::query()
    ->select(['title', 'slug', 'image', 'category_id'])
    ->with(['category:id,title,slug'])
    ->paginate();

¡Ya casi está listo! La vista resources/views/products.blade.php no requiere de cambios; sin embargo, para que la paginación sea útil, debemos agregar los enlaces para avanzar o retroceder en el listado de resultados:

@forelse($products as $product)
    <div class="item">
        <!-- información del producto -->
    </div>
@empty
    <p>No se encontraron productos
@endforelse

{{ $products->links() }}

Al utilizar el método paginate, Laravel retorna un objeto de la clase Illuminate\Pagination\LengthAwarePaginator, este objeto envuelve la colección generada por Eloquent o el constructor de consultas (Illuminate\Database\Eloquent o Illuminate\Support\Collection respectivamente).

links es uno de los métodos que brinda el paginador de Laravel y éste imprimirá el HTML con los enlaces necesarios para la paginación.

Cambiar la cantidad de resultados por defecto con el paginador de Laravel

Por defecto, Eloquent pagina los resultados de 15 en 15, pero podemos personalizar esto como primer argumento del método paginate:

<?php
Product::paginate(20); // Pagina de 20 en 20

O cambiando la propiedad $perPage en el modelo:

<?php
namespace App;

//...

class Product extends Model
{
    protected $perPage = 20;
}

Regresa el navegador y recarga la página para ver el resultado. Podrás ver que la cantidad de productos ha aumentado y el total de páginas ha disminuido.

Consultas ejecutadas por el paginador de Laravel

El paginador genera dos consultas:

Ver consultas en Laravel DebugBar

La primera consulta sirve para contar la cantidad de productos que hay en el sistema y la segunda consulta obtiene los primeros 15 resultados.

Si cambiamos el seeder para generar 100 mil o 1 millón de productos en vez de 1000 y tenemos extrema paciencia, podremos ver que la consulta para contar los productos sube a un tiempo considerable. En mi computador:

  • Contar 1000 registros = 500 microsegundos
  • Contar 100 mil registros = 2 milisegundos
  • 1 millón de registros = 200 milisegundos

En casos así podemos acudir al método simplePaginate:

<?php
// routes/web.php

$products = Product::simplePaginate();

// O:

$products = Product::query()
              //...
              ->simplePaginate();

De regreso al navegador podemos notar que Laravel ya no realiza la consulta para contar la cantidad de resultados. Lo cual reduce de manera considerable el tiempo de procesamiento.

La desventaja de esto es que perdemos la información sobre la cantidad de páginas, puesto que el paginador ahora presenta solo dos opciones para ver la página previa y la siguiente.

Puedes aprender cómo traducir tu aplicación al español si revisas las notas de la lección Validación de datos en Laravel 6.

Personalizar el estilo del paginador de Laravel

Como una nota adicional, si deseas personalizar el HTML generado por el paginador de Laravel utiliza el comando:

#
php artisan vendor:publish --tag=laravel-pagination

Luego personaliza las vistas generadas en resources/views/vendor/pagination/.

También puedes elegir qué vista usar cuando llamas al método links:

<!-- resources/views/products.blade.php -->
{{ $products->links('bootstrap-4') }}

Una mejor práctica es ir a app/Providers/AppServiceProvider.php y cambiar las vistas por defecto:

<?php

namespace App\Providers;

// ...
use Illuminate\Pagination\Paginator;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Paginator::defaultView('vendor.pagination.bootstrap-4');

        Paginator::defaultSimpleView('vendor.pagination.simple-bootstrap-4');
    }

    //...
}

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

Lección anterior Tip de optimización con Eloquent #3: Selecciona columnas específicas Lección siguiente Tip de optimización con Eloquent #5: Usa claves foráneas (índices)