我正在开发基于Symfony 2的项目,需要使用cron任务定期从.csv文档导入150万个产品。
导入目前看起来像这样:
...
Propel::disableInstancePooling();
$fp = fopen($file, 'r');
while ( !feof($fp) ) {
$line = fgets($fp, 2048);
$data = str_getcsv($line, "\t");
$product = new Product();
$product->setId($data[0]);
$product->setTitle($data[1]);
...
$product->save();
}
...
然而,大约5分钟后Apache遇到512MB内存分配并引发以下错误:
Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 78 bytes) in /var/www/vhosts/myapp.local/app/cache/dev/classes.php on line 9451
我已经禁用了Propel的实例池(这在以前的其他框架中的Propel驱动的导入中已经起作用)并且问题仍然存在所以我想知道Symfony 2是否正在执行任何类型的缓存(基于错误被抛出。)
有没有人有过在Symfony 2中执行大型导入的经验,这可以指引我朝着正确的方向发展?
答案 0 :(得分:1)
哦,小伙子,我6个月前就在那里,给你一个小词:交易。
将csv切成碎片,就像在10000行或更少的包中一样,每个包执行1个事务,这样就可以避免向db写入150万次并写入150的开销。
希望能引导您找到一个好的解决方案,我无法将时间从30秒降低,也许您应该考虑使用这种io / cpu绑定任务的离线任务处理器。
此页面是我的圣经: http://propelorm.org/documentation/06-transactions.html
实际上我认为这是网站要求的某种导入操作,如果这是“开发人员”需要做的一次性事情,我会选择Xnoise建议。
答案 1 :(得分:1)
实际上,这个导入应该直接在mysql级别上完成(mysql可以从csv文件读取数据),除非它非常复杂。另一种方法是以增量方式读取文件,生成sql文件并在本机之后将其导入数据库。没有理由直接通过Web应用程序处理如此大的导入,因为您将耗尽内存。
确保您不会立即将整个csv加载到内存中。
额外的解决方案是在php.ini中给php更多内存,并希望最好。 Php不是批量处理大量数据的最佳语言。