【问题标题】:Getting OOM from large dataset从大型数据集中获取 OOM
【发布时间】:2018-06-04 18:23:41
【问题描述】:

我正在尝试从包含 60k 个条目的数组创建电子表格 (XLSX)。当它导出时,它给了我一个带有 PHP OOM 警告的电子表格。

    $spreadsheet = new Spreadsheet();
    $spreadsheet->setActiveSheetIndex(0);
    $activeSheet = $spreadsheet->getActiveSheet();

    $rowIndex = 2;

    foreach ($this->_values as $_val){
        $activeSheet->setCellValueByColumnAndRow(1, $rowIndex, trim($_val['item1']));
        $activeSheet->setCellValueByColumnAndRow(2, $rowIndex, trim($_val['item2']));
        $activeSheet->setCellValueByColumnAndRow(3, $rowIndex, trim($_val['item3']));
        $activeSheet->setCellValueByColumnAndRow(4, $rowIndex, trim($_val['item4']));
        $activeSheet->setCellValueByColumnAndRow(5, $rowIndex, trim($_val['item5']));
        $activeSheet->setCellValueByColumnAndRow(6, $rowIndex, trim($_val['item6']));
        $activeSheet->setCellValueByColumnAndRow(7, $rowIndex, trim($_val['item7']));
        $activeSheet->setCellValueByColumnAndRow(8, $rowIndex, trim($_val['item8']));
        $activeSheet->setCellValueByColumnAndRow(9, $rowIndex, trim($_val['item9']));
        $activeSheet->setCellValueByColumnAndRow(10, $rowIndex, trim($_val['item10']));
        $activeSheet->setCellValueByColumnAndRow(11, $rowIndex, trim($_val['item11']));

        $rowIndex += 1;
    }

    $spreadsheet->garbageCollect();

    $writer = new Xlsx($spreadsheet);
    $writer->setPreCalculateFormulas(false);
    $writer->setUseDiskCaching(true);
    $writer->save("php://temp");

    $spreadsheet->disconnectWorksheets();
    unset($spreadsheet);

【问题讨论】:

  • 尝试将内存限制设置为无限制并检查是否有效
  • 为什么不尝试分批做
  • 我无法设置内存限制。并不是说我不知道​​怎么做,但这不是一个选择,因为代码是在生产服务器上的。批处理也不是一种选择,因为客户希望它在一个文件中
  • 即使您无法在生产环境中使用建议的操作,您也应该尝试使用它们来定位问题。

标签: php out-of-memory phpspreadsheet


【解决方案1】:

内存不足错误是因为您的系统内存不足。假设您的系统有空间,您可以简单地使用 ini_set('memory_limit', '750M'); 之类的 increase the amount of memory

或者,如果不需要 XLSX(即:如果您可以改用 CSV,Excel 仍然可以打开),您可以将数据流式传输到电子表格,而不是一次将其全部加载到内存中,然后打印。看起来像这样:

foreach ($this->_values as $_val){
    for($i=1; $i<=11; $i++) {
        echo trim($_val['item'.$i]);
        if($i<11) echo ",";
    }
    echo "\n";
}

您也可以include the CSV header at the top of the PHP file,这样页面会提示下载,而不是向您显示 CSV 文件的内容。这是 CSV 标头 cal:header("Content-type: text/csv");

【讨论】:

  • 将其转换为 CSV 会导出它,但我更希望它采用 XLSX 格式。
  • @Tanaka 您是否尝试像我在第一段中建议的那样增加内存?这对你有用吗?
  • 我刚刚看到您对原始问题的评论。如果批处理不是一种选择并且增加内存(即使只是对于这个文件,这是我提供的 ini_set 函数所做的)不是一种选择,我认为 CSV 是你最好的答案。
  • 好的,PhpSpreadsheet 无法处理创建具有大型数据集的 XLSX。所以不得不使用CSV。我希望它在未来得到更新。
猜你喜欢
  • 1970-01-01
  • 2013-02-11
  • 2018-07-11
  • 2017-10-08
  • 1970-01-01
  • 2020-09-22
  • 2017-03-06
  • 2012-01-14
  • 1970-01-01
相关资源
最近更新 更多