Tối ưu web app performance trong Laravel (Part 2)
Xin chào các bạn !!!!
Nối tiếp phần 1 chúng ta hãy tiếp tục tìm hiểu một số cách tối ưu performance cho web app laravel nhaaa Ở phần trước, chúng ta đã đề cập đến việc đánh index cho các trường cần thiết trong database và hạn chế vấn đề N+1 query và tối ưu số lượng truy vấn khi làm việc với Laravel, bây giờ chúng ta hãy đến với một số phương pháp tiếp theo nhé
3. Sử dụng paginate khi lấy dữ liệu
Trong một hệ thống Web, chúng ta phải tương tác với một lượng dữ liệu khá lớn. Và nếu ta hiển thị tất cả dự liệu trong một bảng khi số lượng record của bảng đó quá nhiều, người dùng sẽ rất khó khăn trong việc theo dõi dữ liệu cũng như làm chậm hệ thống vì phải truy vấn quá nhiều dữ liệu. Và phân trang là một giải pháp hiệu quả cho vấn đề đó. Trong query builder, Laravel có hỗ trợ phương thức paginate() giúp việc phân trang trở nên dễ dàng hơn.
User::paginate(15)
Khi viết một API để lấy dữ liệu , ta có thể cho phép người dùng truyền vào số lượng record/page để thuận tiện cho việc sử dụng của người dùng.
Mọi người có thể tìm hiểu thêm về cách hoạt động của Paginate trong Laravel qua bài viết sau
4. Sử dụng "raw" để giảm truy vấn số lượng các câu lệnh
Như mọi người đã biết, Laravel hỗ trợ 2 kiểu truy vấn là Eloquent ORM và Query Builder. Với Eloquent ORM, câu truy vấn sẽ ngắn gọn hơn, dễ nhìn và trực quan hơn khi được thể hiện qua Model.
Tuy nhiên, trong nhiều trường hợp câu truy vấn phức tạp , ta có thể dùng Raw query để thực hiện nhằm tiết kiệm thời gian và số lượng câu truy vấn
Ở đây mình có 1 ví dụ Ở trong bảng Posts mình muốn lấy ra 3 thông tin là tổng số bài viết, số bài viết đã publish, số bài viết nháp, với Eloquent, thông thường mình sẽ mất 3 câu query để lấy ra 3 thông tin trên :
$countPosts = Post::count(); // Total Post
$publishedPosts = Post::whereNotNull('published_at')->count(); // Published Post
$draftPosts = Post::whereNull('published_at')->count(); // Draft Post
Với Raw query , ta chỉ mất 1 câu truy vấn cho 3 thông tin cần lấy ra
$posts = Post::query()
->selectRaw("count( case when published_at is not null then 1 end ) as published_post")
->selectRaw("count( case when published_at is null then 1 end ) as draft_post")
->selectRaw("count(id) as total_post")
->first();
5. Bulk Insert / Update trong Laravel
Khi làm việc với Laravel , đôi lúc chúng ta muốn thêm nhiều giá trị cùng một lúc, ta có thể dùng insert() để thêm một mảng dữ liệu vào database thay vì dùng create() với chỉ 1 record được thêm. Tuy nhiên phương thức insert() sẽ chỉ trả về trạng thái true/false mà không trả về đối tượng được tạo như create().
$users = [
[
"username" => "jimmy sanwo"
"year" => "1988"
],
[
"username" => "jimmy sanwo"
"year" => "1988"
],
[
"username" => "jimmy sanwo"
"year" => "1988"
],
]
User::insert($users);
Khác với việc tạo nhiều dữ liệu, việc cập nhật đồng thời nhiều bản ghi gặp nhiều khó khăn hơn khi laravel không hỗ trợ bulk update nên thường mọi người sẽ tự viết hàm bulkUpdate hoặc dùng package bên ngoài. Thường để update nhiều bản ghi, ta sử dụng query builder với lệnh CASE WHEN và đưa vào danh sách id của record kèm danh sách thông tin được update:
public function bulkUpdate(array $values, $column)
{
if (!$values) {
return false;
}
$cases = [];
$ids = [];
$params = [];
foreach ($values as $id => $value) {
$id = (int) $id;
$cases[] = "WHEN {$id} then ?";
$params[] = $value;
$ids[] = $id;
}
$ids = implode(',', $ids);
$cases = implode(' ', $cases);
$params[] = Carbon::now();
return DB::update("UPDATE `tables` SET `" . $column . "` = CASE `id` {$cases} END, `updated_at` = ? WHERE `id` in ({$ids})", $params);
}
Cũng mong Laravel sớm cho phép bulk update thông qua eloquent để thuận tiện hơn cho dev =))))
Tuy nhiên mọi người cũng không nên quá quan trọng số lượng câu query mà quan trọng là tốc độ và resource xử dụng , với việc sử dụng 1 query với thời gian thực thi lâu và tốn nhiều resource và sử dụng nhiều query nhưng với mỗi query thời gian phản hồi nhanh và tiêu tốn ít resource hơn
All rights reserved