我正在使用PHPExcel在.xlsx中生成报告。在初始测试阶段可以使用小数据集(数十行,3张),但现在当在每张表中超过500行的实际生产数据上使用它时,它变得非常慢。生成文件需要48秒,并且在运行包含更多信息的报表时,整个操作都会失败Fatal error: Maximum execution time of 30 seconds exceeded in PHPExcel/Worksheet.php on line 1041
。有时它在另一个PHPExcel文件中,所以我怀疑确切的位置是相关的。
理想情况下,如果可能的话,我想以某种方式加快速度。如果没有,那么至少增加该脚本的执行限制。
到目前为止,我看到的唯一建议是在范围内设置样式而不是单个单元格。不幸的是,我已经在范围内做了我的造型,而且它也很小。还有其他建议吗?
答案 0 :(得分:57)
是否填充了工作表?还是储蓄?你发现太慢了吗?
您如何使用数据填充电子表格?
fromArray()
方法比填充每个单独的单元格更有效,特别是如果您使用Advanced Value Binder自动设置单元格数据类型。如果您使用
为工作表中的每个单元格设置值$objPHPExcel->getActiveSheet()->setCellValue('A1',$x);
$objPHPExcel->getActiveSheet()->setCellValue('B1',$y);
使用
$sheet = $objPHPExcel->getActiveSheet();
$sheet->setCellValue('A1',$x);
$sheet->setCellValue('B1',$y);
这样您只能访问getActiveSheet()
方法一次;
或利用流畅的界面设置多个单元格,只需一次调用$objPHPExcel->getActiveSheet()
$objPHPExcel->getActiveSheet()->setCellValue('A1',$x)
->setCellValue('B1',$y);
您已经评论过将样式应用于细胞范围:
applyFromArray()
一次性设置各种样式设置。如果您在工作簿中使用公式,则在保存时:
使用
$objWriter->setPreCalculateFormulas(false)
禁用在PHPExcel本身内计算公式。
这些只是帮助提升性能的一些提示,并且在论坛帖子中还有更多建议。它们不一定都会有所帮助,太多取决于你的具体工作手册给予任何绝对,但你应该能够提高那么慢的速度。即使是我用于开发的小笔记本也可以比生产服务器更快地编写3个工作表,20列,2,000行Excel 2007文件。
修改强>
如果可以简单地提高PHPExcel本身的速度,我很久以前就已经这么做了。事实上,我经常进行性能测试,看看它的速度如何提高。如果你想要比PHPExcel本身更快的速度,那么就有list of alternative libraries here。
答案 1 :(得分:13)
我也遇到了这个问题。因为这个问题得到了很多看法,所以我会把我的两分钱扔进去。
不要单独设置每个单元格的值,而是使用fromArray()
方法。摘自the wiki。
$arrayData = array(
array(NULL, 2010, 2011, 2012),
array('Q1', 12, 15, 21),
array('Q2', 56, 73, 86),
array('Q3', 52, 61, 69),
array('Q4', 30, 32, 0),
);
$as = $objPHPExcel->getActiveSheet();
$as->fromArray(
$arrayData, // The data to set
NULL, // Array values with this value will not be set
'C3' // Top left coordinate of the worksheet range where
// we want to set these values (default is A1)
);
<强>静态强>
为范围应用样式也比单独设置每个单元格的样式(注意模式??)更快。
$default_style = array(
'font' => array(
'name' => 'Verdana',
'color' => array('rgb' => '000000'),
'size' => 11
),
'alignment' => array(
'horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER,
'vertical' => \PHPExcel_Style_Alignment::VERTICAL_CENTER
),
'borders' => array(
'allborders' => array(
'style' => \PHPExcel_Style_Border::BORDER_THIN,
'color' => array('rgb' => 'AAAAAA')
)
)
);
// Apply default style to whole sheet
$as->getDefaultStyle()->applyFromArray($default_style);
$titles = array(
'Name',
'Number',
'Address',
'Telephone'
);
$title_style = array(
'font' => array(
'bold' => true
),
'fill' => array(
'type' => \PHPExcel_Style_Fill::FILL_SOLID,
'startcolor' => array('rgb' => '5CACEE')
),
'alignment' => array(
'wrap' => true
)
);
$as->fromArray($titles, null, 'A1'); // Add titles
$last_col = $as->getHighestColumn(); // Get last column, as a letter
// Apply title style to titles
$as->getStyle('A1:'.$last_col.'1')->applyFromArray($title_style);
<强>动态强>
我使用PHPExcel检查电子表格中给出的数据以及数据库中的当前数据。由于每个单元格都是单独检查的,我将样式放在一个数组中(null表示没有样式),并使用下面的循环来获取要应用样式的单元格范围。
/*
* $row is previously set in a loop iterating through each
* row from the DB, which is equal to a spreadsheet row.
* $styles = array(0 => 'error', 1 => 'error', 2 => null, 3 => 'changed', ...);
*/
$start = $end = $style = null;
foreach ($styles as $col => $s) {
if (!$style && !$s) continue;
if ($style === $s) {
$end = $col;
} else {
if ($style) {
$array = null;
switch ($style) {
case 'changed':
$array = $this->changed_style;
break;
case 'error':
$array = $this->error_style;
break;
case 'ignored':
$array = $this->ignored_style;
break;
}
if ($array) {
$start = \PHPExcel_Cell::stringFromColumnIndex($start);
$end = \PHPExcel_Cell::stringFromColumnIndex($end);
$as->getStyle($start.$row.':'.$end.$row)->applyFromArray($array);
}
}
$start = $end = $col;
$style = $s;
}
}
答案 2 :(得分:5)
我遇到了同样的问题 - 有大约450行,我试图写入11列数据,而且我一直在对抗30秒超时。通过批量添加所有新行,然后通过并在事后设置单元格内容,我能够将执行时间缩短到2秒或更短。换句话说,我在insertNewRowBefore()的一次调用中插入450行,然后循环并在以后的那些行中设置内容。
像这样:
$num_rows = count($output_rows);
$last_row = $sheet->getHighestRow();
$row = $last_row + 1;
$sheet->insertNewRowBefore($row, $num_rows);
// Now add all of the rows to the spreadsheet
foreach($output_rows as $line) {
$i = 0;
foreach($line as $val) {
// Do your setCellValue() or setCellValueByColumnAndRow() here
$i++;
}
$row++;
}
答案 3 :(得分:2)
我不是使用PHPExcel的专家,但 OfficeOpenXML格式(* .xlsx文件的格式)本身就是一组打包在ZIP存档中的* .xlsx扩展名的XML文件。如果你重视你的表现并知道你将传递什么样的数据,那么构建自己的XLSX生成器,剥离到最重要的功能,或许在数据库层进行一些计算是一个更好的主意。而不是解析整个文档。
要做到这一点,您可以从分析使用较小数据集生成的文件开始(通过将* .xlsx中的扩展名更改为* .zip,解压缩并浏览单个文件的内容)。这样你就可以确定你真正需要的东西并自己生成它(通过创建适当的XML文件并将它们打包成ZIP存档,然后重命名为* .xlsx扩展名)。
还有OfficeOpenXML的规格,它很大(几千页),因此除非你真的想要,否则我不打算阅读它。创建文件以匹配PHPExcel生成它们的方式就足够了。
上面提到的解决方案不包含任何与PHPExcel相关的提示,因为我不是它的专家。我以前对OOXML标准化过程感兴趣,如果有关此标准的知识可以帮助您解决问题,我会很高兴。
答案 4 :(得分:1)
对于列a - amj(~800)且只有~50行的XLSX导出,我也遇到了30秒的边界。为了测试我的程序,我将处理的行数限制为7,这在25秒内有效。
从单个$ objPHPExcel-&gt; getActiveSheet()转到$ sheet(第一个建议)它实际上将有限行数的时间从25秒增加到26秒。
真正帮助我的是用一个简单的$ column_nr变量替换我所有的getHighestDataColumn(),该变量以PHP递增,我从26秒变为7秒。
之后我能够在11秒内处理所有50行。
答案 5 :(得分:0)
我有完全相同的问题。获得了5000行,32列CSV文件,需要永久处理。事实证明,几乎所有的时间都花在了#34;处理&#34;实际上是字符编码,默认设置为将所有内容编码为UTF8。因此,如果您进入config \ excel.php文件并向下滚动到编码,只需将其设置为:
/*
|--------------------------------------------------------------------------
| Import encoding
|--------------------------------------------------------------------------
*/
'encoding' => array(
'input' => '',
'output' => ''
),
仅凭这一点 - 上述文件需要大约8秒才能处理。您可能希望警告您的客户端正确保存CSV。
答案 6 :(得分:0)
在我的情况下,我通过将缓存存储方法更改为内存gzip cache_in_memory_gzip
来提高性能$cm = \PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip;
\PHPExcel_Settings::setCacheStorageMethod($cm);
答案 7 :(得分:0)
我之前从未见过的一个性能提示与添加工作表有关,或更具体地说,是设置工作表的标题。如果添加许多工作表,操作顺序可能会产生巨大影响。对于以下测试,我使用了包含120个填充工作表的电子表格,并计时了创建另外120个空工作表所花费的时间。
首先,使用the docs中显示的步骤:
for ($i = 0; $i < 120; $i++) {
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Sheet Title' . $i);
}
// Time: 12.5605s
the docs中的另一种替代方法:
for ($i = 0; $i < 120; $i++) {
$sheet = new Worksheet($spreadsheet, 'Sheet Title' . $i);
$spreadsheet->addSheet($sheet);
}
// Time: 0.0266s
可以使用setTitle
的第二个参数来弥补上述两种方法之间的大部分性能差距(如果可以的话,请参见the docs):
for ($i = 0; $i < 120; $i++) {
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Sheet Title' . $i, false);
}
// Time: 0.5793s