スポンサーリンク
はじめに
PHPSpreadsheetで大量のデータを読み書きすると「PHP Fatal error: Allowed memory size of …」のようなエラーが出ることがある。文字通りメモリ不足である。
PHPSpreadsheetは便利であるがメモリを食うライブラリで、仕様では1セル辺り1K(64 ビット PHP では 1.6k)のメモリを使用すると書かれている。そのため、例えば「80,000行 × 12列」の帳票を扱う場合は 約960MBのメモリを食うことになる。正直、1回のリクエストで 960MBを超えるメモリ使用量を許容するハイスペックサーバーを用意するのは簡単ではない。
この記事では、PHPSpreadsheetでメモリ使用率を抑える方法について、いくつか紹介する。
複数のファイルを読み書きする場合
複数のファイル・シートを読み込むような場合、disconnectWorksheets
および disconnectCells
で明示的にメモリに保持されたキャッシュをクリアすることで、メモリ使用率を抑えることが可能である。逆にこの関数でキャッシュをクリアせずに、複数のファイル・シートの読み込みを続けた場合、キャッシュがクリアされずにメモリを圧迫する。
$file = ;
$reader = IOFactory::createReader('Xlsx');
$reader->setReadDataOnly(TRUE);
$spreadsheet = $reader->load("./hoge.xlsx");
$sheet = $spreadsheet->getActiveSheet();
//何かしらの処理
$spreadsheet->disconnectWorksheets();
複数のシートを読み込む場合は、対象のシートの処理が終わったタイミングで disconnectCells
でシートのキャッシュを解放します。
$sheet = $sprqweadsheet->getSheet(0);
//1シート目の何かしらの処理
//シートの解放
$sheet->disconnectCells();
/////////////////////////
$sheet = $sprqweadsheet->getSheet(1);
//2シート目の何かしらの処理
//全シートの解放
$spreadsheet->disconnectWorksheets();
スポンサーリンク
1シートに大量のデータを出力する場合
1シート上の大量のデータを読み書きする場合は、上で紹介した disconnectWorksheets
および disconnectCells
でメモリを解放することは出来ない。
対策としては、次の3つが考えられる。
対策1: php.ini でメモリ上限を増やす
php.ini
の設定でメモリの上限を増やす。
memory_limit = 256M
上限を無制限にする場合は -1
を設定する。
memory_limit = -1
対策2:ini_setで一時的にメモリ割り当てを増やす
特定のプロセス(リクエスト)のみメモリの上限を上げたい場合は、ini_set
関数で一時的に変更します。
ini_set('memory_limit', '256M');
対策3:キャッシュをメモリ以外の別の場所に保存する
メモリの上限を引き上げられない場合は、ファイルや Redis
などに、セルのキャッシュを保持させることで、メモリ使用率を抑えることができます。(もしろん性能は落ちます)
■ Redisに保存する
Redisキャッシュを使用するのに必要なパッケージをインストールします。
composer require cache/simple-cache-bridge cache/redis-adapter
Excel ファイルの読み書きを行う前に、次のコードのように、セルのオブジェクトを Redisにキャッシュする設定を行います。
$client = new \Redis();
$client->connect('127.0.0.1', 6379);
$pool = new \Cache\Adapter\Redis\RedisCachePool($client);
$simpleCache = new \Cache\Bridge\SimpleCache\SimpleCacheBridge($pool);
\PhpOffice\PhpSpreadsheet\Settings::setCache($simpleCache);
■ Laravelのキャッシュに保存する
Webフレームワークに Laravelを使用している場合は、Laravelのキャッシュシステムに保存させることもできます。
use PhpOffice\PhpSpreadsheet\Settings;
use Illuminate\Cache\Repository;
use Illuminate\Support\Facades\Cache;
$cache = new Cache();
$cacheStore = $cache::getStore();
$cacheInterface = new Repository($cacheStore);
Settings::setCache($cacheInterface);
スポンサーリンク
まとめ
ここまで紹介してきたとおり、PHPSpreadsheetは結構メモリを食うライブラリで、大量のデータを読み書きする場合には注意が必要です。
あらかじめ大量データを処理すると分かっていて、それがシンプルな Excel処理であれば、
PHP_XLSXWriter などの利用を検討してもよいでしょう。
0 件のコメント:
コメントを投稿