Trung bình Laravel

Tối Ưu Query Laravel Với Eager Loading

Học cách tối ưu truy vấn database trong Laravel bằng eager loading để né vụ N+1 query cho gọn nhẹ, mượt mà.

19 Th06, 2026 3 phút 1,671 Lượt xem 6 Khối code

Tối Ưu Query Laravel Với Eager Loading

Khi làm việc với Eloquent ORM của Laravel, một trong những "sát thủ" hiệu năng phổ biến nhất chính là vấn đề N+1 query. Nó xuất hiện ngay khi anh em load một collection model rồi đụng vào relationship bên trong vòng lặp.

Vấn đề N+1

$posts = Post::all(); // 1 query

foreach ($posts as $post) {
    echo $post->author->name; // +1 query MỖI post
}

Load 50 bài viết là bắn ra 51 query liền: 1 cho posts, cộng thêm 1 cho mỗi author. Nhìn code thì không thấy gì, nhưng chạy dưới tải nặng là chết ngắc.

flowchart TD A[Post all - 1 query] --> B{Loop từng post} B --> C[post.author - query 2] B --> D[post.author - query 3] B --> E[post.author - query 51] style C fill:#fee2e2,stroke:#ef4444 style D fill:#fee2e2,stroke:#ef4444 style E fill:#fee2e2,stroke:#ef4444

Cách fix: eager loading với with()

$posts = Post::with('author')->get(); // tổng cộng 2 query

foreach ($posts as $post) {
    echo $post->author->name; // hết query dư
}

Laravel chạy 1 query lấy posts, rồi 1 query duy nhất kiểu WHERE author_id IN (...) để lấy hết author luôn - 2 query bất kể có bao nhiêu post đi nữa.

Nested & nhiều relationship cùng lúc

// Nhiều relation
$posts = Post::with(['author', 'comments'])->get();

// Relation lồng nhau (cú pháp dấu chấm)
$posts = Post::with('comments.user')->get();

// Ràng buộc relation bằng closure
$posts = Post::with(['comments' => fn ($q) => $q->latest()->limit(5)])->get();

Chỉ load cột nào cần thôi

$posts = Post::with('author:id,name')->get();

Chọn id,name giúp payload nhẹ hều - nhớ luôn kèm foreign key (id), không thôi relation nó không match được đâu.

Eager load sau khi đã có collection

Lỡ có collection rồi thì load relationship sau bằng load():

$posts = Post::all();
$posts->load('author');

Bắt N+1 tự động

Bật strict mode trong service provider để lazy loading tự quăng lỗi lúc dev:

use Illuminate\Database\Eloquent\Model;

Model::preventLazyLoading(! app()->isProduction());

Rút gọn lại

  • with() load trước (2 query); load() load thêm cho collection đã có sẵn.
  • Relationship nào đụng trong vòng lặp thì eager-load liền, đừng để lười.
  • Dùng column selection với closure để chỉ lấy đúng thứ cần.
  • Bật preventLazyLoading lúc dev để bắt N+1 trước khi lên production.
Thử thách tương tác

Thử thách

Luyện tập ngay điều vừa học. Viết lời giải, mở gợi ý nếu bí.

Ngôn ngữPHP

Code khởi tạo

php
$posts = Post::all();

foreach ($posts as $post) {
    echo $post->author->name;
}

Lời giải của bạn

Lời giải · php
$posts = Post::with('author')->get();

foreach ($posts as $post) {
    echo $post->author->name;
}

Cùng chủ đề Laravel