导入/导出大文件,避免内存耗尽错误

时间:2014-02-03 12:40:37

标签: php symfony memory import background-process

在我的应用程序中,我有一个导入功能,允许用户将数据从csv文件导入我的应用程序,并导出现有数据。)

问题是导入的文件可能有很多记录,而在导入方法中我创建了很多相关的对象,因此在某些情况下它会导致内存耗尽错误。

我正在寻找优化代码的方法。我已经在使用$ em-> clear和gc_collect_cycles函数,我知道Doctrine2批处理方法。 可以创建一个后台进程来导入文件(例如运行控制台命令吗?

这种情况的最佳做法是什么? 我知道例如OroCrm Project使用命令作为安装程序,同时向用户显示加载器并且它们的安装运行非常顺利。

期待您的意见。 谢谢。

1 个答案:

答案 0 :(得分:0)

您当然可以运行控制台命令。但是,Doctrine 2并不适合批量操作,很快就会耗尽燃气。

我有一个使用PDO的进程,它定期扫描具有110K记录的csv文件,并更新多达五个不同的表。它甚至可以在我每月5美元的共享主机服务器上运行。

制作PDO服务:

# =============================================================
pdo:
    class: PDO
    arguments:
        dsn:      '%database_dsn%'      # mysql:dbname=appgames
        user:     '%database_user%'
        password: '%database_password%'
    calls:
        - [setAttribute, [ 3, 2]] # \PDO::ATTR_ERRMODE,           \PDO::ERRMODE_EXCEPTION
        - [setAttribute, [19, 2]] # \PDO::ATTR_DEFAULT_FETCH_MODE \PDO::FETCH_ASSOC
        - [setAttribute, [20, 0]] # \PDO::ATTR_EMULATE_PREPARES

准备一些陈述:

public function prepareLevelInsert()
{
    $key = 'levelInsert';

    if (isset($this->prepared[$key])) return $this->prepared[$key];

    $sql = <<<EOT
INSERT INTO levels
       ( id,  name, sport, domain, domainSub, status)
VALUES (:key,:name,:sport,:domain,:domainSub, 'Active')
;
EOT;
    return $this->prepared[$key] = $this->conn->prepare($sql);
}

然后浏览您的文件

// $conn is the PDO object or a 
// DBAL connection object obtained from $entityManager->getConnection();
$conn->beginTransaction();
while($row = fgetcsv($fp))
{
    // Pull level data
    $level = array('name' => $row['levelName'] ... rest of values ...);

    // And insert
    $this->prepareLevelInsert()->execute($level);
}
$conn->commit();

有点单调乏味但速度比使用Doctrine 2快。

相关问题