こんにちは。カヤックモバイル$でコンチとかコンチとかポケットフレンズ コンチを作ってるアラガです。
symfony1.0で大量のレコードに対して1レコードずつ処理をしていくバッチを走らせたところメモリリークしてどうしても途中で処理が終了してしまいました。 調べたところ、既に弊社のsyojiが経験済みでした。(PHPの循環参照ではまった)
が、僕の場合どうしても、このままなんとかしたかったのでなんとかしました。
phpで同様の状況に陥った時に、もっといい方法があれば大募集です。
BEFORE
〜前略〜
$records = BigTablePeer::doSelect(new Criteria());
foreach ($records as $record) {
$subc = new Criteria();
$subdata = SubTablePeer::doSelectOne($subc->add($record->getId()));
// 処理色々
$subdata->save();
$record->save();
}
これだと、数千件でmemoryエラーになってしまうのでファイルを二つに分割;
AFTERE
command.php
〜前略〜
$sub_command = dirname(__file__).DIRECTORY_SEPARATOR.'sub_command.php'
$point = 0;
$limit = 200;
do {
$result = exec("php ".$sub_command." ".$point." ".$limit);
list($total, $rest, $point) = split(",", $result);
} while(0 < $rest);
sub_command.php
〜前略〜
$total = BigTablePeer::doCount(new Criteria());
$c = new Criteria();
$records = BigTablePeer::doSelect($c->setLimit($argv[2])->setOffset($argv[1]));
foreach ($records as $record) {
$subc = new Criteria();
$subdata = SubTablePeer::doSelectOne($subc->add($record->getId()));
// 処理色々
$subdata->save();
$record->save();
}
$next = $argv[1] + $argv[2];
echo ($total).",".($total - $next).",".$next."\n";
このようにスクリプトを分割して少数ずつ外部スクリプトとして実行すれば、この手の問題は回避できます。
美しくはないけど。。。