Оптимизиране на setCellValueExplicit() в PHPExcel

Работя със 700 реда данни в моя Excel.

И добавям в колона този запис:

foreach($data as $k => $v){
   $users ->getCell('A'.$k)->setValue($v['Username']);
   $users->setCellValueExplicit('B'.$k, 
      '=INDEX(\'Feed\'!H2:H'.$lastRow.',MATCH(A'.$k.',\'Feed\'!G2:G'.$lastRow.',0))',
      PHPExcel_Cell_DataType::TYPE_FORMULA);
}

$users означава електронна таблица.

Виждам, че писането на 700 клетки с горното setCellValueExplicit() отнема повече от 2 минути, за да бъде обработено. Ако пропусна този ред, обработката му отнема 4 секунди на същата машина.

2 минути може да са добре, но какво ще стане, ако имам 2000 клетки. Има ли начин да се оптимизира скоростта?

ps: =VLOOKUP е същата бавна като горната функция.


Актуализация

Цялата идея на скрипта: прочетете CSV файл (13 колони и поне 100 реда), запишете го в електронна таблица, създайте нова електронна таблица ($users), прочетете две колони, сортирайте ги въз основа на една колона и я запишете в $users електронна таблица.

Прочетете колоните:

$data = array();
for ($i = 1; $i <= $lastRow; $i++) {
    $user = $Feed ->getCell('G'.$i)->getValue();
    $number = $Feed ->getCell('H'.$i)->getValue();
    $row = array('User' => $user, 'Number' => $number);
    array_push($data, $row);
}

Сортирайте данните

function cmpb($a,$b){
    //get which string is less or 0 if both are the same
    if($a['Number']>$b['Number']){
        $cmpb = -1;
    }elseif($a['Number']<$b['Number']){
        $cmpb = 1;
    }else{
        $cmpb = 0;
    }
    //if the strings are the same, check name
    if($cmpb == 0){
        //compare the name
        $cmpb = strcasecmp($a['User'], $b['User']);
    }
    return $cmpb;
}
usort($data, 'cmpb');

Запишете данни

foreach($data as $k => $v){
   $users ->getCell('A'.$k)->setValue($v['Username']);
   $users ->getCell("B{$k}")->setValueExplicit("=INDEX('Feed'!H2:H{$lastRow},MATCH(A{$k},'Feed'!G2:G{$lastRow},0))",
 PHPExcel_Cell_DataType::TYPE_FORMULA);
}

и също дезадайте данните за паметта:

unset($data);

Така че, ако коментирате линията с setValueExplicit, всичко става по-гладко.


person Diolor    schedule 09.05.2013    source източник
comment
Стойността, която задавате на setCellValueExplicit, е малко нечетлива поради всички тези конкатенации и бягство в единичните кавички. Можете да го замените с "=INDEX('Feed'!H2:H{$lastRow},MATCH(A{$k},'Feed'!G2:G{$lastRow},0))".   -  person Rolando Isidoro    schedule 09.05.2013
comment
@RolandoIsidoro За съжаление не мога да кажа, че видях подобрение в производителността.   -  person Diolor    schedule 09.05.2013
comment
Затова добавих като коментар, а не като отговор. Просто разглеждах изходния код на PHPExcel и не мога да намеря причина за поведението, което описвате. Ще добавя отговор с някои съображения, защото няма да пасне на коментарите. Кажете ми какво мислите за това.   -  person Rolando Isidoro    schedule 09.05.2013
comment
Няма логична причина setCellValueExplicit() да е значително по-бавен от getCell()->setValue(), но можете да опитате getCell()->setValueExplicit(), както Роландо предложи.   -  person Mark Baker    schedule 10.05.2013
comment
P.S. - Извинявам се, че написах неразумен код, не се колебайте да разгледате алтернативи. Няма да ви принуждавам да използвате PHPExcel   -  person Mark Baker    schedule 10.05.2013
comment
@MarkBaker PHPExcel досега е страхотен и удобен за използване. За мен е добър пъзел да се науча да оптимизирам кода си. Просто се опитвам да разбера защо се случва това. Ще стартирам същия скрипт на по-добър сървър   -  person Diolor    schedule 10.05.2013


Отговори (1)


Разглеждайки изходния код на PHPExcel, това е функцията PHPExcel_Worksheet::setCellValueExplicit:

public function setCellValueExplicitByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
{
    return $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow)->setValueExplicit($pValue, $pDataType);
}

За типа данни, който използвате, PHPExcel_Cell_DataType::TYPE_FORMULA, функцията PHPExcel_Cell::setValueExplicit просто изпълнява:

case PHPExcel_Cell_DataType::TYPE_FORMULA:
    $this->_value = (string)$pValue;
    break;

Не мога да намеря логично обяснение за старата информация за изпълнението на тази конкретна инструкция. Опитайте да го замените за следното и ме уведомете, ако има подобрение:

$users ->getCell("B{$k}")->setValueExplicit("=INDEX('Feed'!H2:H{$lastRow},MATCH(A{$k},'Feed'!G2:G{$lastRow},0))", PHPExcel_Cell_DataType::TYPE_FORMULA);

Като последен ресурс моят съвет би бил да проследите изпълнението на инструкцията във времето, за да намерите пречка.

person Rolando Isidoro    schedule 09.05.2013
comment
Благодаря Ви за отговора. Опитах го и намали времето от 2 минути на една минута. Все пак се опасявам, че това е много и доста неразумно. Аз също стартирах скрипта 2-3 пъти и получих Allowed memory size of 134217728 bytes exhausted. 128 мегабайта памет... Още идеи са добре дошли, благодаря - person Diolor; 10.05.2013
comment
Ако можете да поставите някъде набора $data, с който работите, може би мога да опитам да го ускоря. - person Rolando Isidoro; 10.05.2013
comment
Ако и вие имате проблеми с паметта, тогава или трябва да увеличите паметта си, или да използвате кеширане на клетки; но последното ще повлияе на скоростта - person Mark Baker; 10.05.2013
comment
Актуализиран. $data е многоизмерен масив 2x700. - person Diolor; 10.05.2013