PHPExcelを使用して.xlsxでレポートを生成しています。小さいデータセット(10行、3シート)を使用した初期テスト段階では問題ありませんでしたが、各シートに500行を超える実際の実稼働データで使用すると、非常に遅くなります。ファイルを生成するのに48秒かかり、より多くの情報を組み合わせたレポートを実行すると、すべてがFatal error: Maximum execution time of 30 seconds exceeded in PHPExcel/Worksheet.php on line 1041
で失敗します。別のPHPExcelファイルにあることもあるので、正確な場所がその関連性があるとは思いません。
できれば、どうにかして速度を上げたいと思います。そうでない場合は、少なくともこのスクリプトの実行制限を増やします。
これまで見てきた唯一の提案は、個々のセルではなく範囲でスタイルを設定することでした。残念ながら、私はすでに範囲内でスタイリングを行っており、それもかなり最小限です。他の提案はありますか?
ワークシートに入力されていますか?または保存しますか?遅すぎると思う?
スプレッドシートにデータをどのように入力していますか?
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()
を1回呼び出すだけで複数のセルを設定できます
_$objPHPExcel->getActiveSheet()->setCellValue('A1',$x)
->setCellValue('B1',$y);
_
セルの範囲にスタイルを適用することについてコメントしました:
applyFromArray()
を使用して、さまざまなスタイル設定を一度に設定するオプションもあります。ワークブックで数式を使用している場合、保存するとき:
使用する
_$objWriter->setPreCalculateFormulas(false)
_
pHPExcel自体の式の計算を無効にします。
これらはパフォーマンスを向上させるためのいくつかのヒントに過ぎず、フォーラムのスレッドにはさらに多くの提案があります。それらはすべて助けになるとは限りません。絶対値を与えるには特定のワークブックに依存しすぎますが、その遅い速度を改善できるはずです。私が開発に使用する小さなノートブックでも、実稼働サーバーよりも高速に3ワークシート、20列、2,000行のExcel 2007ファイルを作成できます。
[〜#〜] edit [〜#〜]
PHPExcel自体の速度を単純に改善することができたなら、私はずっと前にやっていただろう。現状では、速度を改善する方法を確認するために、常にパフォーマンステストを行っています。 PHPExcel自体が提供できる速度よりも高速にしたい場合は、 代替ライブラリのリスト があります。
私もこの問題に遭遇しました。この質問には非常に多くの意見があるので、私は2セントを投じると思いました。
各セルの値を個別に設定する代わりに、fromArray()
メソッドを使用します。 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;
}
}
私は同じ問題に直面していました-私が書き込もうとしていた11列のデータで約450行があり、30秒のタイムアウトに対して走り続けました。すべての新しい行を一括して追加し、事後にセルの内容を設定することで、実行時間を2秒以下に短縮することができました。つまり、insertNewRowBefore()の1回の呼び出しで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++;
}
私は決してPHPExcelの使用の専門家ではありませんが、OfficeOpenXML形式(* .xlsxファイルの形式)自体は、*。xlsx拡張子。パフォーマンスを評価し、渡すデータの種類を知っている場合は、XLSXジェネレーターを構築することをお勧めします。最も重要な機能は、ドキュメント全体を解析する代わりに、データベース層などで計算を行うことです。
これを行うには、小さなデータセットを使用して生成されたファイルの分析から始めます(拡張子を* .xlsxから* .Zipに変更し、展開して、単一ファイルのコンテンツを参照します)。そうすれば、本当に必要なものを判断して自分で生成することができます(適切なXMLファイルを作成してZipアーカイブにパックし、*。xlsx拡張子に名前を変更します)。
OfficeOpenXML の仕様もあり、これは大きい(数千ページ)ため、本当に必要でない限り読むことを提案しません。 PHPExcelで生成された方法と一致するファイルを作成すれば十分です。
上記のソリューションには、PHPExcelに関連するヒントは含まれていません。これは、私がエキスパートではないためです。ただし、以前はOOXMLの標準化プロセスに興味があり、この標準に関する知識が問題の解決に役立つなら幸いです。
列a-amj(〜800)とわずか50行のXLSXエクスポートの場合、30秒の境界に遭遇しました。プログラムをテストするために、処理する行の量をわずか7に制限し、25秒で機能しました。
個々の$ objPHPExcel-> getActiveSheet()から$ sheet(最初のアドバイス)に行くと、実際には限られた行の時間を25秒から26秒に増やしました。
私が本当に助けたのは、getHighestDataColumn()をすべてPHPでインクリメントされる単純な$ column_nr変数に置き換えることで、26秒から7秒になりました。
その後、11行で50行すべてを処理できました。
私の場合、キャッシュストレージメソッドをメモリ内gzipに変更することでパフォーマンスを向上させましたcache_in_memory_gzip
$cm = \PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip;
\PHPExcel_Settings::setCacheStorageMethod($cm);
私はまったく同じ問題を抱えていました。処理に永遠にかかった5000行、32列のCSVファイルを取得しました。 「処理」に費やされるほとんどすべての時間は、実際にはデフォルトですべてをUTF8にエンコードするように設定された文字エンコードであることがわかります。したがって、config\Excel.phpファイルに移動してエンコードまでスクロールダウンする場合は、次のように設定します。
/*
|--------------------------------------------------------------------------
| Import encoding
|--------------------------------------------------------------------------
*/
'encoding' => array(
'input' => '',
'output' => ''
),
これだけで-上記のファイルの処理には約8秒かかります。ただし、CSVを正しく保存するようにクライアントに警告することもできます。