Laravel nâng cao

Tối ưu Eloquent Query: Đừng để N+1 Problem giết chết ứng dụng Laravel của bạn

Eloquent ORM rất mạnh, nhưng cũng rất dễ dùng sai. Hướng dẫn chi tiết cách phát hiện và xử lý lỗi N+1, tối ưu query và sử dụng Eager Loading hiệu quả.

newspaper

BlogDev Team

25 tháng 12, 2024 schedule 3 phút đọc
Database Optimization Code
Featured Image

Laravel Eloquent ORM là một công cụ tuyệt vời giúp Developer thao tác với Database một cách “thanh lịch” (elegant). Tuy nhiên, sự tiện lợi này thường đi kèm cái giá đắt nếu bạn không hiểu rõ những gì đang diễn ra bên dưới (“Under the hood”).

Vấn đề kinh điển nhất: N+1 Query Problem.

N+1 Query là gì?

Hãy xem đoạn code sau để lấy danh sách bài viết và tên tác giả:

// 1 query để lấy tất cả bài viết
$posts = Post::all(); 

foreach ($posts as $post) {
    // N query để lấy author cho từng bài viết
    echo $post->author->name; 
}

Nếu bạn có 100 bài viết:

  • 1 Query lấy danh sách post.
  • 100 Query lấy author cho từng post.
  • Tổng cộng: 101 queries. 😱

Đây chính là N+1 Problem. Nếu danh sách lên tới 1000 items, Database của bạn sẽ “bốc hơi”.

Giải pháp: Eager Loading

Laravel cung cấp giải pháp cực đơn giản: with().

// Chỉ tốn đúng 2 queries
$posts = Post::with('author')->get();

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

Eloquent sẽ chạy:

  1. SELECT * FROM posts
  2. SELECT * FROM authors WHERE id IN (1, 2, 3, ...)

Sau đó nó tự động ghép (map) kết quả lại ở tầng Application. Hiệu năng tăng hàng trăm lần.

Những kỹ thuật tối ưu khác

1. Chỉ lấy cột cần thiết (Select Specific Columns)

Đừng bao giờ select * nếu bạn chỉ cần idname.

Sai:

$users = User::all(); // Lấy cả bio, password, remember_token... tốn RAM vô ích

Đúng:

$users = User::select('id', 'name')->get();

2. Chunking kết quả lớn

Khi xử lý hàng chục nghìn record (ví dụ gửi mail marketing), đừng dùng get() hay all(). Dùng chunk().

User::chunk(100, function ($users) {
    foreach ($users as $user) {
        // Gửi mail...
    }
});

Nó giúp RAM server không bị tràn (Memory Leak) vì chỉ load từng gói nhỏ 100 user vào bộ nhớ.

3. Dùng Index trong Database

Mọi sự tối ưu ở code PHP đều vô nghĩa nếu cột bạn WHERE, ORDER BY hay JOIN không có Index trong Database. Hãy chắc chắn bạn đã đánh index cho các cột quan trọng (ví dụ: email, status, created_at).

Tổng kết

“Premature optimization is the root of all evil” (Tối ưu quá sớm là nguồn gốc của mọi tội lỗi). Tuy nhiên, N+1 Query không phải là tối ưu sớm, nó là lỗi kỹ thuật (Technical Debt) cần tránh ngay từ dòng code đầu tiên.

Hãy cài đặt Laravel Debugbar hoặc Telescope ngay hôm nay để soi xem ứng dụng của bạn đang chạy bao nhiêu query mỗi request nhé!

history_edu Góc học tập & giải trí

Thử Thách Kiến Thức Lịch Sử?

Khám phá hàng trăm câu hỏi trắc nghiệm lịch sử thú vị tại HistoQuiz. Vừa học vừa chơi, nâng cao kiến thức ngay hôm nay!

Chơi Ngay arrow_forward