gpt4 book ai didi

php - 导出大型 CSV 文件

转载 作者:可可西里 更新时间:2023-10-31 22:12:11 25 4
gpt4 key购买 nike

我有一个 mysql 表,其中每条记录可以有无限的自定义字段(EAV 模型,这无关紧要),每个字段可以有无限的选项,每个选项可以有无限的值。
现在我正在尝试构建一个导出工具,该工具将导出所有这些自定义字段及其值,即:每个字段的名称 => 值对。这不是重要的部分,它只是为了强调我们正在讨论针对单个记录的大量 mysql 查询,并且导出的大小将非常大。

对于我的主表中的每一行,我必须执行大约 100 个单独的 sql 查询来获取字段、字段选项和字段选项值。这些查询非常快,因为它们都使用了正确的索引,但我们仍然在谈论对单个记录的 100 个查询,我希望在我的主表中有大约 50k 的记录只是开始。

现在,我做的是:

set_time_limit(0);
ini_set('memory_limit', '1G');
ini_set("auto_detect_line_endings", true);

$count = $export->count();
$date = date('Y-m-d-H-i-s');
$fileName = CHtml::encode($export->name) .'-'. $date . '.csv';

$processAtOnce = 100;
$rounds = round($count / $processAtOnce);

header("Content-disposition: attachment; filename={$fileName}");
header("Content-Type: text/csv");

$headerSet = false;
for ($i = 0; $i < $rounds; ++$i) {

$limit = $processAtOnce;
$offset = $i * $processAtOnce;
$rows = $export->find($limit, $offset);

if (empty($rows)) {
continue;
}

$outStream = fopen('php://output', 'w');

if (!$headerSet) {
fputcsv($outStream, array_keys($rows[0]), ',', '"');
$headerSet = true;
}

foreach ($rows as $row) {
fputcsv($outStream, array_values($row), ',', '"');
}

echo fgets($outStream);

fclose($outStream);
}

基本上我会计算所有记录并为它们“分页”以便导出,然后遍历页面以避免一次加载太多的 sql 结果。
我想知道这是否是一种有效的方法?有什么想法吗?

我的替代方法是计算所有记录,将它们分成“页面”,并为每个页面执行一个 ajax 请求(在前一个请求成功完成后调用的递归函数)。在做ajax请求的时候,可能一次处理1k条记录(这1k条也会像上面的例子一样被拆分,例如在内部运行10次得到100个结果),把它们写入一个临时目录(比如part-1.csv, part-2.csv) 并在处理完所有记录后,从包含所有 csv 部分的文件夹中创建一个存档,并强制浏览器下载它,然后将其从服务器中删除(window.location.href 从最后一次 ajax 调用)。
这是上面的一个很好的选择吗?

请注意,我的目标是限制内存使用量,这就是为什么我认为第二种方法对我更有帮助。

请告诉我你的想法。
谢谢。

最佳答案

我的 final方法是第二种方法,经过大量测试后我得出结论,就我而言,第二种方法在内存使用方面要好得多,即使完成整个导出的时间更长,也不会这很重要,因为 GUI 将使用有关导出的实时统计信息进行更新,并且在等待导出完成时总体而言是一种良好的用户体验。

这些是我采取的步骤:
1) 加载页面并向服务器发出第一个 ajax 请求。
2) 服务器将一次读取前 1000 条记录,每批 100 条记录,以避免从 mysql 一次返回许多结果。
3) 将结果写入文件part-x.csv,其中x为ajax发送的请求号。
4) 当没有更多记录添加到文件中时,最后一次 ajax 调用将创建存档,并删除包含 part-x.csv 文件的文件夹。然后服务器将返回一个名为“download”的 json 参数,其中包含通过 PHP 下载文件的 url(fopen + fread + flush + fclose,然后取消链接存档文件)
5) 使用“download”参数,浏览器将执行 window.location.href = json.download 并强制下载文件。

我知道,这样的工作更多,但正如我所说,最终结果似乎比我第一次使用的方式一次加载要好。

关于php - 导出大型 CSV 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19070693/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com