【问题标题】:Doctrine 2 bulk insert/update memoryDoctrine 2 批量插入/更新内存
【发布时间】:2014-03-08 01:34:35
【问题描述】:

考虑这段代码(包装在函数中):

    $manager = $this->manager; // local ref
    $q = $manager->createQuery('select c from VendorFeedBundle:Category c');
    $iterableResult = $q->iterate();
    $i = 0;
    $batchSize = 500;

    foreach($iterableResult as $row) {
        $category = $row[0];

        $struct = explode(' ' . $this->separator . ' ', $category->getPath());
        unset($struct[count($struct) - 1]);
        $path = implode(' ' . $this->separator . ' ', $struct);

        if (!$parent = $this->repo->findOneBy(['path' => $path])) {
            continue;
        }

        $category->setParent($parent);

        // flush every x entities
        if (($i % $batchSize) == 0) {
            echo 'Flushing batch...' . "\n";
            echo 'Memory: ' . $this->getReadableSize(memory_get_usage()) . "\n";

            $manager->flush();
            $manager->clear();

            echo 'After batch...' . "\n";
            echo 'Memory: ' . $this->getReadableSize(memory_get_usage()) . "\n";
        }
        ++$i;
    }

    // flush the remaining
    $manager->flush();
    $manager->clear();

它在我的终端中记录以下内容:

Creating tree...
Memory: 14.91 MB
Flushing batch...
Memory: 18.46 MB
After batch...
Memory: 18.79 MB
Flushing batch...
Memory: 21.01 MB
After batch...
Memory: 23.29 MB
Flushing batch...
Memory: 25.36 MB
After batch...
Memory: 27.87 MB
Flushing batch...
Memory: 29.88 MB
.... etc

getReadAbleSize 方法不会将任何变量泄漏到全局范围或任何东西。 我已经阅读并遵循了关于教条 2 批量插入/更新(批处理)的建议: http://docs.doctrine-project.org/en/latest/reference/batch-processing.html

我做错了什么? 每 500 个项目增加 3~4 MB 内存对我来说似乎是一个(小)泄漏。

旁注:我需要以这种方式更新项目,因为我的系统分为 2 个进程;首先插入类别,然后更新父关系。

我的类别类是一个基本的 Doctrin2 实体,其中添加了一些 Gedmo 扩展(树、可翻译、可时间戳) 见:http://pastie.org/private/oiiyf54zjuouhiqjsjislg

我的完整脚本(迭代和更新类别): http://pastie.org/private/k5x240vr4taepczhqa4tva

【问题讨论】:

  • 我花了相当多的时间尝试使用 Doctrine 2 优化这类过程,但得出的结论是,你不能从这里开始。切换到基于低级别 PDO 的流程。有点痛苦,但我可以在每月 5 美元的共享主机上轻松处理 10 万多条记录。
  • 尝试在 prod 环境中运行命令或使用--no-debug 选项。

标签: php symfony memory doctrine-orm memory-leaks


【解决方案1】:
  1. 将 SQL 记录器设置为 null

$em->getConnection()->getConfiguration()->setSQLLogger(null);

  1. $em->clear() 之后手动调用函数gc_collect_cycles()

$em->clear(); gc_collect_cycles();

不要忘记将zend.enable_gc设置为1,或者在使用gc_collect_cycles()之前手动调用gc_enable()

  1. 如果您从控制台运行命令,请添加 --no-debug 选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-02
    相关资源
    最近更新 更多