excel百万数据异步导出

小叽叽叽叽

问题描述

我用队列来写入xlsx 用 PhpOffice\PhpSpreadsheet 还是会出现内存溢出

为此你搜索到了哪些方案及不适用的原因

我后面用 PHP-Xlswriter 这个导出,无法追加写入
我用fputcsv 这个可以追加写入,但是无法创建新的sheet
大家都是咋办的

1371 9 7
9个回答

gddd

我这边是分批次导出

  • 小叽叽叽叽 2023-10-08

    我也是分成好几批2w一批数据,放进队列里面, PhpOffice\PhpSpreadsheet 但是这个内容大了就会移出,难道要分文件才行吗

  • gddd 2023-10-08

    一定要新建sheet吗?不然使用fputcsv就可以了,分批导出到csv 再压缩到文件 10多万行 是没问题的

  • 小叽叽叽叽 2023-10-08

    最好是放一个xlsx,我想看下大家有没有更好的,我现在就是fputcsv后生成一个压缩文件

  • 小叽叽叽叽 2023-10-08

    大佬我还有一个问题,就是,你是直接把查询好的数据分成块传递进去,还是划定一个范围,然后在队列里面查询进行写入

  • gddd 2023-10-08

    我整个导出都是队列执行的,提交导出条件到队列,分块查询导出到csv,然后压缩

  • 小叽叽叽叽 2023-10-08

    好的谢谢

Chance

Xlswriter 可以固定内存一次导出, 不用分批追加导出

  • 暂无评论
软饭工程师
SillyDog
  • 暂无评论
muyu

Xlswriter 支持追加导入,实测百万数据几十秒吧~

  • 晚安。 17天前

    看了他的文档 ,追加导入 是怎么写的

  • 小叽叽叽叽 9天前

    追加写入不支持,我这里追加写入的意思是,一个文件关闭了,再打开,进行写入,我后面用的fputcsv这个,这个对表格没有样子要求感觉效果挺好的

muyu

不知道你是如何处理的,我这边是按照这种格式导出的,速度还行


// 处理路径文件以及文件名称
[$file, $object] = static::handelExcel($path, $name);
// 准备导出的数据
$i = 0;
Item::filter($filter)->chunkById(1000, function ($items) use ($object, &$i) {
    $items->each(function ($item) use ($object, &$i) {
        ++$i;
        $object = $object->data([
            [
                $item->title,
                $item->barcode,
                $item->category,
            ],
        ]);
    });
});
  • 暂无评论
weijer

前端轮询处理不就行了,后端处理还废内存

  • 暂无评论
liuxingke

https://github.com/openspout/openspout 非常好用,不管多大的数据都只占用几兆内存

  • 暂无评论
diguojin

楼上muyu的方案是一个很好的思路: 如果是因为一次读取太多数据行导致内存不够 这就可以解决问题。
另外,还可以考虑使用html格式 生成简单xls。

public function outPutHtmlExcel($titles, $rows, $filename)
    {
        header("Content-type:application/vnd.ms-excel");
        header("Content-Disposition:filename=" . $filename . ".xls");
        echo "<body><meta charset='UTF-8'><table border='1'>";
        echo "<tr>";
        foreach ($titles as $title) {
            echo "<th>$title</th>";
        }
        echo "</tr>";
        foreach ($rows as $row) {
            echo "<tr>";
            foreach ($titles as $k => $v) {
                if (isset($row[$k])) {
                    $export = str_replace(["\t", "\r", "\n", "\n\r"], '', $row[$k]) . "\t";
                    echo "<td style='mso-number-format: \@'>$export</td>";
                } else {
                    echo "<td></td>";
                }
            }
            echo "</tr>";
        }
        echo "</table></meta></body>";
        exit();
    }

只要把上面rows 那部分逻辑按照 chunkById 的形式 改造一下,我想应该可以解决你的问题。

  • diguojin 7天前

    我这里简单echo出去了,你可以考虑把它追加到特定文件里。

🔝