+1

Sử dụng Lazy Collection để export 100,000 bản ghi

Lazy Collection là gì

Lazy Collection được giới thiệu bới Joseph Silber trong Laravel 6.0. Lazy collection là một class cho phép chúng ta duyệt các phần tử trong mảng. Layzy collection sửa dụng PHP generator để cho phép chúng ta làm việc với tập dữ liệu rất lớn và giữ cho mức sử dụng bộ nhớ ở mức thấp.

Bài toán đặt ra

Giá sử rằng CSDL của chúng tao có bảng chứa 100,000 bản ghi và chúng ta muốn lấy tất cả dữ liệu này, có thể xuất ra csv hoặc hiển thị lên cho người dùng

Nếu bạ sử dụng hàm all() trong Laravel Eloquent, hầu hết bộ nhớ của server sẽ được sử dụng để thực hiện truy vấn này. Việc truy vấn này sẽ làm 2 phần : đầu tiên là nạp tất các bản ghi được lấy ra từ CSDL, sau đó lấy đẩy bản ghi này vào collection. Với 100,000 bản ghi việc này sẽ ảnh hưởng đến hệ thống, vì ngoài chức năng này ra hệ thống của chúng ta cũng còn phải thực hiện nhiều chức năng khác (search, insert, update v...v..)

Thật may Laravel 6.0 đã cung cấp cho chúng ta Laravel Collection đễ làm việc với tập dữ liệu lớn với memory sử dụng thấp. Vậy chúng ta cùng bắt đầu nào 😃

Cài đặt môi trường

1. Install composer

php composer-setup.php --install-dir=bin --filename=composer
mv composer.phar /usr/local/bin/composer

2. Install laravel

composer global require laravel/installer

3. Creata new project

laravel new test-lazy-collection

4. Make database

Cài đặt biến DB_DATABASE, DB_USERNAME, DB_PASSWORD trong file .env

5. Tạo seeder data

php artisan make:seeder UsersTableSeeder

Tạo random data

public function run()
    {
        DB::table('users')->truncate();
        for($i=0; $i<=100; $i++){
            factory(App\User::class, 1000)->create();
        }
    }

Update factory data

$factory->define(App\User::class, function (Faker $faker) {  
	    return [  
	        'name' => $faker->name,  
	        'email' => $faker->unique()->safeEmail,  
	        'email_verified_at' => now(),  
	        'password' => bcrypt('123456'), // password  
	        'remember_token' => Str::random(10),  
	    ];  
	});

6. Run seed data

php artisan db:seed

Tạo logic code xử lý export dữ liệu

1. Tạo routes

Route::get('/write', 'UsersController@write');  
Route::get('/lazyWrite', 'UsersController@lazyWrite');  

2. Thêm method checkDirOrMake() trong UserController

private function checkDirOrMake($dirname){  
	     $filename = $dirname . "/";  
	  
	     if (!file_exists($filename)) {  
	         mkdir($dirname, 0777);  
	     }  
	 }  

Hàm checkDirOrMake() sẽ kiểm tra và tạo folder nếu nó có tồn tại hay không

3. write() function để export dữ liệu ra csv

public function write(){  
	        $directory = storage_path("uploads");  
	  
	        $this->checkDirOrMake($directory);  
	  
	        $file = fopen($directory."/contacts.csv","w+");  
	  
	        $users = \App\User::all();  
	  
	        foreach($users as $user) {  
	            $user = $user->toArray();  
	            fputcsv($file, $user);  
	        }  
	  
	        fclose($file);  
	    }  

4. lazyWrite() để export dữ liệu dùng Lazy Collection

public function lazyWrite(){  
  
        $directory = storage_path("uploads");  
  
        $this->checkDirOrMake($directory);  
  
        $file = fopen($directory."/lazy_contacts.csv","w+");  
  
        $users = \App\User::cursor()  
        ->each(function ($user) use ($file) {  
            $user = $user->toArray();  
            fputcsv($file, $user);  
        });  
  
        fclose($file);  
    }  

Thay vì sử dụng all() chúng ta sẽ sử dụng method cursor()

5. Run virtual server

php artisan serve

6. Chạy exoprt data

Export bình thường

http://localhost:8000/write

Export sử dụng lazy collection

http://localhost:8000/lazyWrite

7. Kết quả

Khi sử dụng export thông thường memory sẽ tốn rất nhiều trong khi sử dụng http://localhost:8000/lazyWrite việc export 100,000 bản ghi rất dễ dàng và tốn ít memory hơn rất nhiều

Kết luận

Việc sử dụng Lazy Collection sẽ tăng performance cho việc xử lý các tập kết quả lớn, nhưng sẽ là không tối ưu khi làm việc với tập dữ liệu nhỏ. Sử dụng Lazy Collection sẽ tùy vào bài toán cụ thể.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí