- vừa được xem lúc

Giải quyết vấn đề N+1 trong quan hệ cha - con vô tận bằng Eager Loading

0 0 182

Người đăng: Phát Nhâm

Theo Viblo Asia

Vấn đề

Trong khi phát triển ứng dụng, chắc hẳn các bạn đã gặp phải trường hợp đệ quy cha-con trong khi phát triển các dự án, ví dụ như cây thư mục như sau:

id name parent_id
1 A null
2 B 1
3 C 1
... ... ...

Trong bài viết này mình sẽ lấy ví dụ về QuestionFolder, thư cây thư mục chứa câu hỏi của hệ thống trắc nghiệm. Thông thường chúng ta sẽ tạo 2 relationship ở Model như sau:

// Model QuestionFolder.php
public function childs()
{ return $this->hasMany('App\Models\QuestionFolder', 'parent_id', 'id');
} public function parent()
{ return $this->belongsTo('App\Models\QuestionFolder', 'parent_id', 'id');
}

Vậy khi chúng ta cần lấy ra Collection tất cả các thư mục con (và cả thư mục con của thư mục con nữa) của một thư mục nào đó:

// Model QuestionFolder.php
public function allChildFolders()
{ $child_folders = [$this]; $folders = [$this]; while(count($folders) > 0) { $nextFolders = []; foreach ($folders as $folder) { $child_folders = array_merge($child_folders, $folder->childs->all()); $nextFolders = array_merge($nextFolders, $folder->childs->all()); } $folders = $nextFolders; } return new Collection($child_folders);
}

Bây giờ chạy xem kết quả nào:

// Route web.php
Route::get('test-recursive', function() { dump(\App\Models\QuestionFolder::findOrFail(27)->all_child_folders);
});

Mọi thứ vẫn cứ ok, bạn vẫn có được kết quả mong muốn. Nhưng tận 101 lượt truy vấn, quá nhiều query. Trong một ứng dụng có vài chục thư mục thì có vẻ ổn, tuy nhiên nếu số lượng thư mục lên đến hàng ngàn, hay chục ngàn, Laravel sẽ phải truy vấn hàng chục ngàn lần, và CSDL của bạn sẽ như cái mềm rách ☹

Recursive Relationship & Eager Loading

Trong Laravel có một chức năng rất tiện lợi để giải quyết những trường hợp N+1 query đó chính là Eager Loading.

Nhưng ở trường hợp này, chúng ta không biết cây thư mục này sâu bao nhiêu để có thể gọi phương thức with(). Vì vậy chúng ta sẽ bổ sung vào một quan hệ là allChilds:

// Model Folder.php
public function allChilds()
{ return $this->childs()->with('allChilds');
}

Và sửa hàm allChildFolders() lại một xíu:

public function allChildFolders()
{ $child_folders = [$this]; $folders = [$this]; while(count($folders) > 0) { $nextFolders = []; foreach ($folders as $folder) { $child_folders = array_merge($child_folders, $folder->allChilds->all()); $nextFolders = array_merge($nextFolders, $folder->allChilds->all()); } $folders = $nextFolders; } return new Collection($child_folders);
}

Ta tạo thêm một route khác để test xem nào

// Route web.php
Route::get('test-recursive', function() { dump(\App\Models\QuestionFolder::findOrFail(27)->allChildFolders);
});

Và đây là kết quả:

Awesome! Đây là bài viết đầu tiên trên Viblo, hy vọng là các bạn thích bài viết này, happy coding ?

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 361

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 452

- vừa được xem lúc

Sử dụng Swagger để xây dựng API documentation

Giới thiệu về Swagger. RESTful API là một tiêu chuẩn dùng trong việc thiết kế API cho các ứng dụng web (thiết kế Web services) để tiện cho việc quản lý các resource.

0 0 1k

- vừa được xem lúc

Ví dụ CRUD với Laravel và Vuejs.

1. Cài đặt Laravel. composer create-project --prefer-dist laravel/laravel vuelaravelcrud. .

0 0 163

- vừa được xem lúc

Một số tips khi dùng laravel (Part 1)

1. Show database query in raw SQL format. DB::enableQueryLog(); // Bật tính năng query logging. DB::table('users')->get(); // Chạy truy vấn bạn muốn ghi log.

0 0 84

- vừa được xem lúc

Inertiajs - Xây dựng Single Page App không cần API

Tiêu đề là mình lấy từ trang chủ của https://inertiajs.com/ chứ không phải mình tự nghĩ ra đâu nhé :v. Lâu lâu rồi chưa động tới Laravel (dự án cuối cùng mình code là ở ver 5.8), thế nên một ngày đẹp trời lượn vào đọc docs ver 8.

0 0 242