1. Laravel
  2. PHP

Mengatasi Permasalahan N+1 Query di Laravel

N+1 Query adalah suatu masalah yang terjadi ketika kita memerlukan untuk load data child dari relasi parent-child dimana kita melakukan banyak query select pada child data. N+1 disini artinya adalah 1 query untuk parent dan N adalah jumlah record pada table child. Pada artikel ini kita akan membahas bagaimana mengatasi permasalahan N+1 query di Laravel.

Untuk memahami lebih lanjut mengenai N+1 query, mari kita buat sebuah skenario untuk menghasilkan permasalahan query ini.

Sebagai contoh, kita memiliki sebuah database skema seperti ini.

Pada contoh ini bisa kita lihat bahwa 1 user bisa memiliki banyak posts (user hasMany posts) dan ini berarti kita akan memiliki 2 Model yaitu User dan Post.

Pada model User kita akan mendefinisikan hasMany relation dan pada model Post kita akan mendefinisikan belongsTo relation.

class User extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

class Post extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Ini adalah contoh sederhana dari has many / belongs to relation di Laravel. Selanjutnya, mari kita mencoba untuk menampilkan seluruh posts untuk salah satu user.

$user = App\User::first();
$posts = $user->posts;

Untuk memeriksa query yang dihasilkan dengan kode diatas, kita akan menggunakan package laravel debugbar yang telah kita bahas dalam artikel Package wajib yang harus di install di Laravel.

Laravel Debugbar
Hasil Query

Tidak ada masalah pada query diatas, karena kita hanya menampilkan data dari 1 user. Bagaimana jika kita lakukan sebaliknya, kita perlu menampilkan 5 posts beserta dengan user yang membuat post tersebut.

Sebagai contoh, kita perlu menampilkan daftar posts dengan UI seperti ini

Post UI

Untuk menghasilkan tampilan di atas, langkah pertama yang kita lakukan adalah membuat query untuk mendapatkan daftar posts, kemudian gunakan relasi ke user untuk ditampilkan di view.

Controller

<?php

namespace App\Http\Controllers;

use App\Post;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::limit(5)->get();

        return view('posts.index', [
            'posts' => $posts,
        ]);
    }
}

View

Pada view kita akan menggunakan kode kurang lebih seperti ini

@foreach ($posts as $post)
    <p>{{ $post->title }} written by {{ $post->user->name }}</p>
@endforeach

Kode diatas akan menghasilkan data yang sesuai dengan yang kita perlukan dalam sisi tampilan, akan tetapi apakah kita telah menggunakan query yang benar? Mari kita lihat query yang dihasilkan pada debugbar toolbar.

Laravel Debugbar

Seperti kita lihat, query pada debugbar toolbar menunjukan kita memiliki 6 query statement dan 5 duplikat query pada halaman ini. Inilah yang kita disebut sebagai N+1 query, 1 query untuk menampilkan daftar posts, dan N (dalam kasus ini 5) query untuk mendapatkan user yang membuat post tersebut.

Tidak dapat dipungkiri bahwa Eloquent ORM sangat membantu kita dalam melakukan aktifitas query ke database, akan tetapi ada kasus kasus tertentu yang harus kita perhatikan sebagai developer. Salah satu contohnya adalah kasus N+1 query ini.

Mengatasi N+1 Query di Laravel

Lalu jika Eloquent ORM menghasilkan duplikat query untuk kasus diatas, bagaimana cara kita mengatasi permasalah N+1 query ini di Laravel? Jawabannya adalah Eager Loading. Saya rasa semua framework yang memiliki Active Record / ORM telah menyediakan fitur ini secara default termasuk Laravel.

Eager Loading Laravel

Pada kasus diatas, kita memiliki 6 query statement dengan 5 duplikat query, dengan Eager Loading kita bisa mengurangi jumlah operasi ini menjadi 2 query. Kita bisa menggunakan eager loading dengan menggunakan method with.

<?php

namespace App\Http\Controllers;

use App\Post;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::with('user')->limit(5)->get();

        return view('posts.index', [
            'posts' => $posts,
        ]);
    }
}

Setelah menambahkan method with pada kode diatas, kita telah mengurangi jumlah query yang di eksekusi menjadi 2. Hal ini tentu saja akan meningkatkan performa load website dibanding sebelumnya.

Laravel Debugbar

Seperti itulah cara penggunaan Eager Loading pada Laravel untuk mengatasi permasalahan N+1 query. Eloquent memang memberikan kemudahan bagi developer untuk melakukan query, akan tetapi kita tetap harus memperhatikan query yang dihasilkan dari kode yang kita buat ketika menggunakan Eloquent. Jangan sampai kita menggunakan Eloquent untuk kecepatan development tanpa memikirkan performa dari query yang dihasilkan.

Comments to: Mengatasi Permasalahan N+1 Query di Laravel

    Your email address will not be published. Required fields are marked *

    Attach images - Only PNG, JPG, JPEG and GIF are supported.