50

PHPExcelを使用して.xlsxでレポートを生成しています。小さなデータセット(数十行、3シート)を使用した初期のテスト段階では問題ありませんでしたが、各シートに500行を超える実際の本番データで使用すると、非常に遅くなります。ファイルを生成するのに48秒かかります。より多くの情報を組み合わせたレポートを実行すると、すべてが。で失敗しFatal error: Maximum execution time of 30 seconds exceeded in PHPExcel/Worksheet.php on line 1041ます。別のPHPExcelファイルにある場合もあるので、正確な場所がそれほど適切であるとは思えません。

理想的には、可能であれば、なんとかしてスピードアップしたいと思います。そうでない場合は、少なくともこのスクリプトの実行制限を増やしてください。

これまでに見た唯一の提案は、個々のセルではなく範囲でスタイルを設定することでした。残念ながら、私はすでに範囲内でスタイリングを行っており、それもかなり最小限です。他に何か提案はありますか?

4

8 に答える 8

63

ワークシートにデータを入力していますか?または保存しますか?遅すぎると思いますか?

スプレッドシートにデータをどのように入力していますか?

  • fromArray()特にAdvancedValueBinderを使用してセルのデータ型を自動的に設定する場合は、この方法を使用すると、個々のセルにデータを入力するよりも効率的です。
  • を使用してシート内の個々のセルごとに値を設定する場合

    $objPHPExcel->getActiveSheet()->setCellValue('A1',$x);
    $objPHPExcel->getActiveSheet()->setCellValue('B1',$y);
    

    使用する

    $sheet = $objPHPExcel->getActiveSheet();
    $sheet->setCellValue('A1',$x);
    $sheet->setCellValue('B1',$y);
    

    getActiveSheet()そのため、メソッドにアクセスできるのは1回だけです。または、流暢なインターフェイスを利用して、1回の呼び出しで複数のセルを設定します。$objPHPExcel->getActiveSheet()

    $objPHPExcel->getActiveSheet()->setCellValue('A1',$x)
                                  ->setCellValue('B1',$y);
    

セルの範囲にスタイルを適用することについてコメントしました。

  • applyFromArray()さまざまなスタイル設定を一度に設定するために使用するオプションもあります。
  • 単に範囲にスタイルを適用するのではなく、列または行にスタイルを適用できると、はるかに効率的です。

ブックで数式を使用している場合、保存するとき:

  • 使用する

    $objWriter->setPreCalculateFormulas(false)
    

    PHPExcel自体の数式の計算を無効にします。

これらはパフォーマンスを向上させるためのヒントのほんの一部であり、フォーラムのスレッドにはさらに多くの提案があります。それらはすべて必ずしも役立つわけではなく、絶対値を与えるには特定のワークブックに大きく依存しますが、その遅い速度を改善できるはずです。私が開発に使用している小さなノートブックでさえ、3ワークシート、20列、2,000行のExcel2007ファイルを実稼働サーバーよりも高速に書き込むことができます。

編集

PHPExcel自体の速度を単純に向上させることができれば、私はずっと前にそうしていました。現状では、速度をどのように改善できるかを確認するために、常にパフォーマンステストを行っています。PHPExcel自体が提供できるよりも速い速度が必要な場合は、ここに代替ライブラリのリストがあります

于 2011-05-12T20:48:15.500 に答える
14

私もこの問題に遭遇しました。この質問は非常に多くのビューを取得するので、私は私の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;
    }
} 
于 2015-08-04T16:15:07.127 に答える
6

私は同じ問題に遭遇していました-私が書き込もうとしていた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++;
}
于 2012-04-02T19:58:11.473 に答える
1

私はPHPExcelの使用に精通しているわけではありませんが、OfficeOpenXML形式(* .xlsxファイルの形式)自体は、拡張子が*.xlsxのZIPアーカイブにパックされたXMLファイルのグループです。パフォーマンスを重視し、渡すデータの種類がわかっている場合は、全体を解析するのではなく、独自のXLSXジェネレーターを構築し、最も重要な関数に絞り込み、データベースレイヤーなどで計算を行うことをお勧めします。資料。

これを行うには、より小さなデータセットを使用して生成されたファイルの分析から始めることができます(拡張子を*.xlsxから*.zipに変更し、解凍して、単一ファイルの内容を参照します)。そうすれば、本当に必要なものを判断して自分で生成できます(適切なXMLファイルを作成してZIPアーカイブにパックし、名前を変更して* .xlsx拡張子を付ける)。

大きい(数千ページ) OfficeOpenXMLの仕様もあるので、本当に読みたくない限り読むことはお勧めしません。PHPExcelによって生成された方法と一致するファイルを作成するだけで十分です。

私は専門家ではないため、上記のソリューションにはPHPExcel関連のヒントは含まれていません。私は以前、OOXMLの標準化プロセスに興味を持っていましたが、この標準に関する知識が問題の解決に役立つと幸いです。

于 2011-05-12T20:29:56.480 に答える
1

列a-amj(〜800)とわずか〜50行のXLSXエクスポートの場合も、30秒の境界に遭遇しました。プログラムをテストするために、処理される行の量を7つに制限しました。これは、25秒で機能しました。

  1. 個々の$objPHPExcel->getActiveSheet()から$ sheet(最初のアドバイス)に移行すると、実際には、限られた行数の時間が25秒から26秒に増加しました。

  2. 私が本当に助けてくれたのは、すべてのgetHighestDataColumn()をPHPでインクリメントされる単純な$column_nr変数に置き換えることでした。26秒から7秒になりました。

その後、11秒で50行すべてを処理することができました。

于 2015-07-08T15:31:30.197 に答える
1

これまで見たことのないパフォーマンスのヒントの1つは、ワークシートの追加、より具体的には、ワークシートのタイトルの設定に関するものです。多くのワークシートを追加する場合、操作の順序が大きな影響を与える可能性があります。次のテストでは、120個のワークシートが入力されたスプレッドシートを使用し、さらに120個の空のワークシートを作成するのにかかる時間を計測しました。

まず、ドキュメントに示されている手順を使用します。

for ($i = 0; $i < 120; $i++) {
    $sheet = $spreadsheet->createSheet();
    $sheet->setTitle('Sheet Title' . $i);
}
// Time: 12.5605s

第二に、ドキュメントからの代替方法:

for ($i = 0; $i < 120; $i++) {
    $sheet = new Worksheet($spreadsheet, 'Sheet Title' . $i);
    $spreadsheet->addSheet($sheet);
}
// Time: 0.0266s

上記の2つの方法の間のパフォーマンスのギャップのほとんどは、次の2番目のパラメーターを使用して埋めることができますsetTitle(この場合、安全である場合は、ドキュメントを参照してください)。

for ($i = 0; $i < 120; $i++) {
    $sheet = $spreadsheet->createSheet();
    $sheet->setTitle('Sheet Title' . $i, false);
}
// Time: 0.5793s
于 2020-10-06T16:49:55.003 に答える
0

私はまったく同じ問題を抱えていました。処理に永遠にかかった5000行32列のCSVファイルを取得しました。「処理」に費やされる時間のほとんどは、実際にはすべてをデフォルトでUTF8にエンコードするように設定されている文字エンコードであることがわかります。したがって、config \ excel.phpファイルに移動し、エンコーディングまでスクロールダウンする場合は、次のように設定します。

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

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

    ),

これだけで-上記のファイルの処理には約8秒かかります。ただし、CSVを正しく保存するようにクライアントに警告することをお勧めします。

于 2016-10-25T11:55:35.793 に答える
0

私の場合、キャッシュの保存方法をメモリ内に変更することでパフォーマンスを向上させましたgzip cache_in_memory_gzip

$cm = \PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip;
\PHPExcel_Settings::setCacheStorageMethod($cm);
于 2017-07-07T13:19:30.297 に答える