PHPExcel очень медленный – способы улучшения?

Я генерирую отчеты в .xlsx, используя PHPExcel. Это было нормально на начальных этапах тестирования с небольшими наборами данных (десятки строк, 3 листа), но теперь, когда он использует его на реальных производственных данных с более чем 500 рядами на каждом листе, он становится невероятно медленным. 48 секунд, чтобы сгенерировать файл, а при запуске отчета, который объединяет больше информации, все происходит с Fatal error: Maximum execution time of 30 seconds exceeded in PHPExcel/Worksheet.php on line 1041 . Иногда это в другом файле PHPExcel, поэтому я сомневаюсь, что точное местоположение соответствует.

В идеале, я бы хотел как-то ускорить его, если это возможно. Если нет, то, по крайней мере, увеличьте предел выполнения для этого скрипта.

Единственное, что я видел до сих пор, это стиль в диапазонах вместо отдельных ячеек. К сожалению, я уже делаю свой стиль в диапазонах, и он тоже минимален. Любые другие предложения?

    Заполняет ли он рабочий лист? или сохранения? что вы находите слишком медленным?

    Как вы заполняете таблицу данными?

    • Использование метода fromArray () более эффективно, чем заполнение каждой отдельной ячейки, особенно если вы используете расширенное связывание значений, чтобы автоматически устанавливать типы данных ячеек.
    • Если вы устанавливаете значения для каждой отдельной ячейки в листе, используя

       $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 столбцов, 2000 строк Excel 2007 быстрее, чем ваш производственный сервер.

    РЕДАКТИРОВАТЬ

    Если бы можно было просто улучшить скорость PHPExcel, я бы давно это сделал. Как бы то ни было, я постоянно тестирую производительность, чтобы увидеть, как его скорость может быть улучшена. Если вам нужны более быстрые скорости, чем может дать PHPExcel, то здесь есть список альтернативных библиотек .

    Я столкнулся с этим вопросом. Думал, что я брошу свои два цента, так как у этого вопроса возникает так много просмотров.

    Установка значений ячейки

    Вместо того, чтобы устанавливать значение для каждой ячейки отдельно, используйте метод fromArray() . Взято и изменено из вики .

     $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 для проверки данных, данных в электронной таблице, с текущими данными в базе данных. Поскольку каждая ячейка проверяется индивидуально, я помещаю стили в массив (нуль без стиля) и использую цикл ниже, чтобы получить диапазон ячеек для применения стиля.

     /* * $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; } } 

    Я столкнулся с той же проблемой – было около 450 строк с 11 столбцами данных, которые я пытался писать, и я продолжал работать против 30-секундного таймаута. Я смог получить время выполнения до 2 секунд или меньше, добавив все мои новые строки в массе, а затем просмотрел и установил содержимое ячейки после факта. Другими словами, я вставляю 450 строк в один вызов для insertNewRowBefore (), а затем прокручиваю и устанавливаю контент в этих строках позже.

    Вот так:

     $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++; } 

    Я никоим образом не специалист по использованию PHPExcel, но формат OfficeOpenXML (формат файлов * .xlsx) сам по себе представляет собой группу файлов XML, упакованных в ZIP-архив с расширением * .xlsx . Если вы оцениваете свою производительность и знаете, какие данные вы будете передавать, возможно, лучше создать собственный генератор XLSX , урезать до самых важных функций, возможно сделать некоторые вычисления на уровне базы данных и т. Д. Вместо того, чтобы разбор целого документ.

    Для этого вы можете начать с анализа файлов, созданных с использованием меньших наборов данных (путем изменения расширения из * .xlsx в * .zip, распаковки и просмотра содержимого отдельных файлов). Таким образом, вы сможете определить, что вам действительно нужно, и создать его самостоятельно (создав соответствующие файлы XML и упаковывая их в ZIP-архив, а затем переименовав расширение * .xlsx).

    Существует также спецификация OfficeOpenXML , которая является большой (несколько тысяч страниц), поэтому я не предлагаю ее читать, если вы действительно этого не хотите. Создание файлов в соответствии с тем, как они были созданы PHPExcel, должно быть достаточно.

    Решение, упомянутое выше, не содержит никаких связанных с PHPExcel советов, потому что я не эксперт в этом. Однако я ранее интересовался процессом разработки OOXML, и был бы рад, если бы знания об этом стандарте помогли бы вам решить вашу проблему.

    Для экспорта XLSX с столбцами a-amj (~ 800) и только ~ 50 строк я также столкнулся с 30-секундной границей. Чтобы проверить мою программу, я ограничил количество обработанных строк до 7, которые работали через 25 секунд.

    1. переходя от отдельного $ objPHPExcel-> getActiveSheet () к $ sheet (первый совет), он фактически увеличил время на ограниченном количестве строк с 25 секунд до 26 секунд.

    2. То, что действительно помогло мне, заменило весь мой getHighestDataColumn () простой переменной $ column_nr, которая была увеличена в PHP, я перешел от 26 секунд до 7 секунд.

    После этого я смог обработать все 50 строк за 11 секунд.

    У меня была такая же проблема. Получил 5000 строк, 32 столбца CSV-файла, который потребовался навсегда для обработки. Получается, что почти все время «обработка» – это фактически кодировка символов, которая по умолчанию кодирует все UTF8. Поэтому, если вы заходите в свой файл config \ excel.php и прокрутите вниз до кодировки, просто установите его как:

     /* |-------------------------------------------------------------------------- | Import encoding |-------------------------------------------------------------------------- */ 'encoding' => array( 'input' => '', 'output' => '' ), 

    При этом один – вышеупомянутый файл занимает около 8 секунд для обработки. Возможно, вы захотите предупредить своего клиента, чтобы он правильно сохранил CSV.

    В моем случае я увеличил производительность, изменив метод хранения кеша в память. Gzip cache_in_memory_gzip

     $cm = \PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip; \PHPExcel_Settings::setCacheStorageMethod($cm);