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

Дайте этому попытку, это обошлось без задания, имеющего необходимость измениться/добавить много существующего кода.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

property для функции нужно два callable аргументы. дайте им обертки лямбды (который это передает экземпляр как свой первый аргумент), и все хорошо.

43
задан SaltyNuts 12 May 2011 в 20:08
поделиться

7 ответов

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

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

  • Использование метода 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.

Это всего лишь несколько советов, которые помогут повысить производительность, и в темах форума предлагается множество других. Все они не обязательно помогут, слишком многое зависит от вашей конкретной рабочей тетради, чтобы дать какие-то абсолюты, но вы должны быть в состоянии улучшить эту медленную скорость. Даже небольшой блокнот, который я использую для разработки, может написать файл Excel 2007 с 3 рабочими листами, 20 столбцов и 2000 строк быстрее, чем ваш рабочий сервер.

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

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

57
ответ дан 26 November 2019 в 22:53
поделиться

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

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

Вместо установки значения для каждой ячейки отдельно, используйте метод 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)
);

Styling Cells

Static

Также быстрее применять стили для диапазона, чем устанавливать стиль для каждой ячейки индивидуально (замечая шаблон ??).

$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;
    }
} 
13
ответ дан 26 November 2019 в 22:53
поделиться

Я столкнулся с той же проблемой - у меня было около 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++;
}
5
ответ дан 26 November 2019 в 22:53
поделиться

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

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

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

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

1
ответ дан 26 November 2019 в 22:53
поделиться

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

/*
|--------------------------------------------------------------------------
| Import encoding
|--------------------------------------------------------------------------
*/
    'encoding' => array(

        'input'  => '',
        'output' => ''

    ),

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

0
ответ дан 26 November 2019 в 22:53
поделиться

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

$cm = \PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip;
\PHPExcel_Settings::setCacheStorageMethod($cm);
0
ответ дан 26 November 2019 в 22:53
поделиться

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

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

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

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

1
ответ дан 26 November 2019 в 22:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: