fputcsv+mysql pdo nobuffer
-
要点:
设置mysql参数,不使用客户端(php)缓冲区,结果集存在mysql服务端
MYSQL_ATTR_USE_BUFFERED_QUERY=false -
优点:
速度快(一百万级十几秒即可),避免内存溢出,csv可以用excel打开 -
缺点:mysql服务端压力过大,csv需要自己处理文本格式,csv用excel打开也是104万行数限制
-
代码:
$timestart = microtime(true);
$startMemory = memory_get_usage();
$sql = 'select * from ti_log';
$pdo = new\PDO('mysql:host=127.0.0.1;dbname=sd_ka', 'root', 'root');
$pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$rows = $pdo->query($sql);
$filename = date('Ymd') . '.csv';//设置文件名
header('Content-Type:text/csv');
header("Content-Disposition:attachment;filename={$filename}");
$out = fopen('php://output', 'w');
fputcsv(
$out, [
'log_id',
'store_code',
'member_id',
'code',
'product_name',
'product_code',
'product_type',
'query_count'
]
);
foreach ($rows as $row) {
$line = [
$row['log_id'],
$row['store_code'],
$row['member_id'],
$row['code'],
$row['product_name'],
$row['product_code'],
$row['product_type'],
$row['query_count']
];
fputcsv($out, $line);
}
fclose($out);
$memory = round((memory_get_usage() - $startMemory) / 1024 / 1024, 3) . 'M' . PHP_EOL;
info('执行内存为为' . $memory);
info('执行时间为' . (microtime(true) - $timestart));
使用laravel包maatwebsite/excel
-
要点:
使用FromQuery()中的query()自动将数据chunk后执行,但是大数据量下写入excel内存溢出。可以追加queue()方法丢入队列,然而对lumen的queue不支持。
或者使用eloquent的cursor()实现,FromCollection中返回cursor(),然而对with()类型的不友好,会有大量的whereIn执行 -
优点:
laravel推荐,功能强大,表格功能丰富 -
缺点:
还是容易内存溢出,支持10万以内的导出 -
代码:
namespace App\Exports;
use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromQuery
{
use Exportable;
public function query()
{
return Invoice::query();
}
}
(new InvoicesExport)->queue('invoices.xlsx');
namespace App\Exports;
use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromCollection
{
use Exportable;
public function collection()
{
return Invoice::query()->cursor();
}
}
(new InvoicesExport)->store('invoices.xlsx');
php扩展xlswriter
-
文档:xlswriter
-
要点:
使用eloquent的cursor()或者chunk()后单条插入 -
优点:
功能较强大 -
缺点:
还是可能内存溢出,支持60万以内的导出,需要安装扩展 -
代码
$config = ['path' => storage_path('app/' . $filePath)];
$excel = new \Vtiful\Kernel\Excel($config);
// constMemory内存模式 fileName普通模式
$excel->constMemory($downloadTask['name'] . $this->fileExtension)
->header($exportObj->headings())
->setColumn('A:R', 20);
TiCodeLog::query()
->where($this->where)
->chunkById(3000, function ($data) use ($exportObj, $excel) {
$data = $exportObj->formatData($data);
foreach ($data as $item) {
foreach ($item as $col => $column) {
$excel->insertText($this->index + 1, $col, $column);
}
$this->index++;
}
unset($data);
$data = null;
}, 'log_id');
$excel->output();