Vấn đề N+1 query trong Laravel (kỹ thuật Eager Loading)



Trần Thanh Luân / 13-01-2017

Nếu ko sử dụng đúng cách thư viện ORM của Laravel thì ta rất dễ bị rơi vào vấn đề N+1

class Book extends Model {

    public function author()

    {

        return $this->belongsTo(‘App\Author’);

    }

}

Bây giờ ta sẽ lặp tất cả các cuốn sách như sau

foreach (Book::all() as $book)

{

    echo $book->author->name;

}

Đoạn code trên đầu tiên sẽ lấy ra tất cả các cuốn sách, sau đó ở mỗi vòng lặp nó lại truy vấn tới bảng author để lấy ra tên các tác giả. Vậy nếu trong database có 25 cuốn sách thì nó sẽ truy vấn tới database tổng cộng là 26 lần (tính cả 1 lần nó lấy book:all). OK, như vậy là không ổn rồi. Giờ để khắc phục vấn đề này thì laravel cung cấp cho chúng ta một kỹ thuật như sau

foreach (Book::with(‘author’)->get() as $book)

{

    echo $book->author->name;

}

Đối với vòng lặp trên nó chỉ thực thi 2 câu truy vấn

select * from books

 

select * from authors where id in (1, 2, 3, 4, 5, …)

Nếu có nhiều bảng cần lấy ra thì ta cũng có thể viết như sau

$books = Book::with(‘author’, ‘publisher’)->get();

Nếu các bảng có ràng buộc về quan hệ, ví dụ như ta cần lấy cả thông tin liên hệ của tác giả nhưng nó nằm ở một bảng khác thì câu lệnh sau đây sẽ lấy luôn cả 2 bảng author và contact

$books = Book::with(‘author.contacts’)->get();

Nếu cần chỉ định thêm điều kiện ở câu truy vấn thì làm như sau

$users = User::with([‘posts’ => function($query)

{

    $query->where(‘title’, ‘like’, ‘%first%’);

}])->get();

hoặc có thể bổ sung cả điều kiện sắp xếp

$users = User::with([‘posts’ => function($query)

{

    $query->orderBy(‘created_at’, ‘desc’);

 

}])->get();


to-top