Export excel dữ liệu lớn bằng Maatwebsite 3.1 bị timeout
Mình có dùng package Maatwebsite để làm xuất Excel thì bị timeout khi export nhiều dữ liệu, mình đã dùng ->queue() hoặc ShouldQueue nhưng vẫn không được. Đây là code của mình
File xử lý Export
<?php
namespace App\Exports;
use App\Models\Txn;
use Illuminate\Queue\SerializesModels;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithEvents;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class TxnsExport implements FromQuery, ShouldQueue, WithHeadings, ShouldAutoSize, WithMapping, WithEvents
{
use Exportable, SerializesModels;
/**
* @return array
*/
public function registerEvents(): array
{
return [
AfterSheet::class => function(AfterSheet $event) {
$styleArray = [
'font' => [
'bold' => true,
],
'alignment' => [
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
],
];
$cellRange = 'A1:W1'; // All headers
$event->sheet->getDelegate()
->getStyle($cellRange)
->applyFromArray($styleArray);
},
];
}
public function headings(): array
{
return [
'Mã người dùng',
'Mã giao dịch',
'Loại giao dịch',
'Trạng thái',
'Từ/Đến',
'Số tham chiếu',
'Số tham chiếu ngân hàng',
'Số dư đầu',
'Số tiền',
'Phí',
'Số dư cuối',
'Thời gian'
];
}
/**
* @var Txn $txn
*/
public function map($txn): array
{
return [
$txn->user_id,
$txn->id,
$txn->type_label,
$txn->stat_label,
$txn->src_des,
$txn->ref_no,
$txn->bank_ref_no,
number_format($txn->opening_balance, 0, ',', '.'),
number_format($txn->amount, 0, ",", "."),
number_format($txn->fee_amount, 0, ",", "."),
number_format($txn->balance, 0, ",", "."),
($txn->created_at == '0000-00-00 00:00:00' || $txn->created_at == '-0001-11-30 00:00:00') ? '' :
date('d-m-Y | H:i:s',strtotime($txn->created_at)),
];
}
public function query()
{
return Txn::select('id','user_id','created_at','type','stat','src_des','ref_no','bank_ref_no','opening_balance','amount','fee_amount','balance','created_at')
->orderBy('id','desc');
}
}
Controller
public function exportExcel()
{
return (new TxnsExport)->download('txns_'.date('YmdHis').'.xlsx');
}
3 CÂU TRẢ LỜI
Bạn thử config max-execution-time của php lên xem. Khả năng cao do export mất quá nhiều thời gian vượt quá timeout của php.
Với việc export bạn có thể dùng package fast-excel xem. cái Maatwebsite nó tích hợp quá nhiều thứ dẫn đến tốn bộ nhớ cũng như tốc độ không cao.
Fast-excel họ có test tốc độ so với Maatwebsite (Don't trust benchmarks).
chỉnh thời gian timeout lên thì khi dữ liệu lớn hơn nữa thì lại phải tăng thời gian đấy lên bạn ơi @@, mình đang không biết sao cái queue nó lại không chạy
@TuanAnh9996 nhưng mình nghĩ trc hết nên xem lại xem xử lý ntn vì với 10k dữ liệu cũng tầm 10s thôi. bỏ queue đi xem bt có chạy ko đã.
Mà mình đang ko hiểu sao dùng queue mà bạn lại return download thế kia nhỉ? nếu viết như vậy đâu ra kết quả gì vì queue là background job. Hay chỗ đó bạn muốn lưu lại file export? nếu muốn lưu phải dùng kiểu khác.
@le.vinh.thien mình dùng export và download luôn thì với tầm 1k bản ghi, 100 cột thì thời giân tầm 1 phút liệu có ổn không b?
@tab99 bạn thử debug xem khi export tốn nhiều thời gian nhất vào phần nào(query, create file, download?) từ đó cải thiện.
@le.vinh.thien mình có xem debug của laravel + trình duyệt nhưng mình chưa biết check time phần nào(query, create file, download) b có thể chỉ mình được không?
@tab99 mỗi đoạn xử lý bạn hãy in ra log time, sau đó check logs của laravel thôi.
ví dụ
// controller
public function export() {
$diffTime = microtime(true);
// phần logic query DB
//....
$diffTime = microtime(true) -$diffTime;
Log::debug( $diffTime);
// phần logic query xử lý dữ liệu
//....
$diffTime= microtime(true) - $diffTime;
Log::debug( $diffTime);
// phần tạo xls file
//....
$diffTime= microtime(true) - $diffTime;
Log::debug( $diffTime);
return ...
}
Mình cũng gặp lỗi tương tự khi cố export khoảng 25k rows, cuối cùng mình chọn giải pháp là sử dụng laravel chunk query khi load từ database để load khoảng 1k rows mỗi lần và dùng hàm fputcsv() của PHP để write file sau đó cho client download file đó về, cũng mất khoảng 2 - 3p. Tuy nhiên thì Maatwebsite cũng hỗ trợ export from query. Bạn tìm hiểu tại đây: https://docs.laravel-excel.com/3.1/exports/from-query.html Hope it helps
@duynam.dev mình cũng dùng from query của Maatwebsite mà tình hình khả quan cho đến khi mình load 35k rows đổ lên, time out vỡ mồm
Không biết bạn thớt đã giải quyết vấn đề này được chưa nhỉ? Mình cũng đang gặp vấn đề tương tự (
https://github.com/rap2hpoutre/fast-excel#benchmarks mình dùng thằng này và đã giải quyết đk rồi