Giới thiệu

Trong các dự án Laravel, Eloquent là ORM mạnh mẽ giúp làm việc với cơ sở dữ liệu một cách trực quan. Tuy nhiên, khi không tối ưu, các truy vấn Eloquent có thể gây ra hiện tượng N+1, tiêu tốn tài nguyên và làm chậm thời gian phản hồi của API.

Vấn đề N+1 và cách khắc phục

Hiện tượng N+1 xuất hiện khi chúng ta lặp qua một tập hợp bản ghi và trong mỗi vòng lặp lại thực hiện một truy vấn phụ để lấy dữ liệu liên quan. Ví dụ:

<?php
$users = User::all();
foreach ($users as $user) {
    $posts = $user->posts; // Truy vấn riêng cho mỗi người dùng
}
?>

Để tránh, Laravel cung cấp phương thức with() để thực hiện eager loading:

<?php
$users = User::with('posts')->get(); // Chỉ một truy vấn duy nhất
?>

Sử dụng select để giảm lượng dữ liệu trả về

Đôi khi chúng ta chỉ cần một vài cột của bảng. Việc lấy toàn bộ cột sẽ tăng kích thước dữ liệu truyền qua mạng. Sử dụng select() để chỉ định những cột cần thiết:

<?php
$users = User::select('id', 'name', 'email')
             ->with(['posts:id,user_id,title'])
             ->get();
?>

Chunk và Lazy Collections cho dữ liệu lớn

Khi xử lý hàng triệu bản ghi, việc tải toàn bộ vào bộ nhớ sẽ gây quá tải. Laravel hỗ trợ chunk()lazy() để xử lý dữ liệu theo lô:

<?php
User::chunk(500, function ($users) {
    foreach ($users as $user) {
        // Xử lý mỗi người dùng
    }
});
?>

Hoặc sử dụng Lazy Collections:

<?php
foreach (User::lazy() as $user) {
    // Xử lý từng bản ghi mà không chiếm nhiều bộ nhớ
}
?>

Thêm chỉ mục (Index) vào cơ sở dữ liệu

Việc tạo chỉ mục trên các cột thường được dùng trong điều kiện where hoặc join sẽ giảm đáng kể thời gian thực thi truy vấn. Ví dụ, tạo chỉ mục trên cột email:

<?php
Schema::table('users', function (Blueprint $table) {
    $table->index('email');
});
?>

Sử dụng cache cho các truy vấn tĩnh

Laravel Cache có thể lưu trữ kết quả truy vấn trong một khoảng thời gian nhất định, giảm tải cho cơ sở dữ liệu. Cách thực hiện đơn giản:

<?php
$users = Cache::remember('active_users', 600, function () {
    return User::where('status', 'active')->get();
});
?>

Sử dụng Raw Queries cho các truy vấn phức tạp

Đôi khi Eloquent không thể tối ưu được một truy vấn phức tạp, ví dụ khi cần thực hiện các phép tính tổng hợp hoặc sub‑query sâu. Khi đó, sử dụng DB::select() để viết SQL thuần sẽ cho phép tối ưu tốt hơn.

<?php
$results = DB::select("
    SELECT u.id, u.name, COUNT(p.id) AS post_count
    FROM users u
    LEFT JOIN posts p ON p.user_id = u.id
    WHERE u.status = ?
    GROUP BY u.id, u.name
    HAVING post_count > ?
", ['active', 10]);
?>

Giám sát và phân tích query với Laravel Debugbar

Công cụ Laravel Debugbar cho phép hiển thị danh sách các query được thực thi trong mỗi request, thời gian thực thi và số lượng. Khi phát hiện query chậm, chúng ta có thể nhanh chóng tối ưu.

Để cài đặt:

composer require barryvdh/laravel-debugbar --dev

Sau khi cài đặt, Debugbar sẽ tự động hiển thị ở phía dưới trình duyệt trong môi trường development.

Kết luận

Áp dụng các kỹ thuật trên sẽ giúp tối ưu hiệu suất của Eloquent, giảm thời gian phản hồi và tiết kiệm tài nguyên server. Nếu muốn nắm vững toàn bộ quy trình tối ưu Laravel từ cơ bản đến nâng cao, Tham khảo khóa học "Lập trình web PHP & MySQL với Laravel Framework" tại đây.