CakePHPでCSV出力時にメモリ不足に陥らないために


思わぬ落とし穴

まず、CSV出力自体はマニュアルや参考資料が豊富に揃っているのでそれほど困らないかと思います。
そう。この手軽さゆえに以下のようなケースに陥りがちです(かく言う私も・・・

・テスト環境でCSV出力を実装
・テスト環境でテストデータをもとに色々なパターンでCSV出力
・テストも問題無かったので本番環境に実装
・本番環境でCSV出力実行! ・・・しばらくグルグル・・・
・まだグルグル・・・・・・シュン・・
!!!
まさかのメモリ不足による処理落ち・・

はい。理由は本番環境での数万件のデータに対してCSV出力機能が耐え切れなくなったのですね。。
あぁ、テスト環境でダミーデータ数万件用意して負荷テストをするべきだった・・・時すでに遅し・・

そうならないためにも

以下に、件数が多くてもデータを分割して出力することによりメモリ不足を回避する方法について
紹介したいと思います。(データの分割方法に焦点をあて、CSV出力方法については割愛します)

CakepPHP

//100件ずつ分割して
$term = 100;
$this->Model->begin();
$cnt = $this->Model->find('count');
$cnt = (int)ceil($cnt / $term);

//分割した回数分ループ
for ($k = 0; $k < $cnt; $k++) {

    //100件取り出す
    $params['order'] = ['id' => 'asc'];
    $params['offset'] = $k * $term;
    $params['limit']  = $term;
    $data = $this->Model->find('all', $params);

    foreach ($data as $i => $v) {
        //ここでCSVに書き込み
    }
}
//全て書き込みが終わったらcloseして出力
$this->Model->rollback();

以上となります。

ポイント

  • データを分割してCSVに書き出す(分割する単位はレコードの長さなどを考慮して調整)
  • きちんとテスト環境でもダミーデータを投入して出力確認してみる