1

我正在开发一个基于 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 中执行大型导入的经验,可以为我指明正确的方向?

4

2 回答 2

1

哦,男孩,我 6 个月前在那里,给你一个小字:交易。

将 csv 切成小块,例如在 10000 行或多或少的包中,每个包执行 1 个事务,这样可以避免向 db 写入 150 万次并写入 150 次的开销。

希望能指导您找到一个好的解决方案,我无法将时间从 30 秒缩短,也许您应该考虑为这类 io/cpu 绑定任务使用离线任务处理器。

目前这个页面是我的圣经: http: //propelorm.org/documentation/06-transactions.html

编辑

实际上,我认为这是该站点需要的某种导入操作,如果这是您“开发人员”需要做的一次性事情,我会选择 Xnoise 建议。

于 2012-12-27T19:30:36.650 回答
1

实际上,这个导入应该直接在 mysql 级别进行(mysql 可以从 csv 文件中读取数据),除非它非常复杂。另一种方法是增量读取文件,生成一个 sql 文件,然后本地将其导入数据库。没有理由让 Web 应用程序直接处理如此大的导入,因为您将耗尽内存。

确保不要一次将整个 csv 加载到内存中。

额外的解决方案是在 php.ini 中给 php 更多的内存,并希望最好。php 不是批量处理大量数据的最佳语言。

于 2012-12-27T19:37:30.473 回答