【问题标题】:How to improve performace of LARGE imports using Doctrine 2如何使用 Doctrine 2 提高 LARGE 导入的性能
【发布时间】:2014-08-21 19:22:12
【问题描述】:

我有大约 100 万条记录需要导入。我一直在网上寻找改进和加速这个过程的方法。目前,我的应用程序连接到 1 个数据库,对大约 220 万行的表进行选择,此选择持续大约需要 10-13 秒。我正在使用此查询选择 10,000 行。

$results = $em->getRepository('...')->createQueryBuilder('x')
              ->where('...')
              ->setFirstResult($index)
              ->setMaxResults($maxResults)
              ->getQuery()
              ->getResult();

然后我继续遍历这些行中的每一行并在另一个数据库中进行 2 次查找,使用这些实体创建一个新实体并使用事务一次插入所有 10,000 个新实体。

$secondEm->transactional(function($em){
    foreach($results as $result){
        $value1 = $em->getRepository('A')->findOneBy(array('value'=>$result->getValue()));
        $value2 = $em->getRepository('B')->findOneBy(array('value'->$result->getValue()));
        $newEntity = new Entity();
        $newEntity->setValue1($value1)->setValue2($value2);
        $em->persist($newEntity);
    }
    $em->flush();
});
$secondEm->clear();

我遇到的问题是每次后续插入的导入时间都会逐渐变大。前 10,000 个大约需要 60 秒,第二个大约需要 100 秒,然后从那里开始,每个新插入似乎增加了大约 5-10 秒。

我已经读过,对于 innodb 表进行大型插入,您应该禁用 foreign_key_checks 和 unique_checks,但我不知道如何为原则事务插入执行此操作。

我们将不胜感激有关如何禁用这些检查甚至是更好的方法来执行此导入的任何建议。

状态

选择查询现在似乎也随着时间的推移而增加。最后一个查询:

$maxResults = 10000;
$index = 470000;

选择耗时 97 秒,导入耗时 173 秒。

重要 这个过程每个请求发生一次,我有一个 javascript 操作,它将自动提交一个空白表单,这一切都发生在 POST 上,我意识到这可能会更好地从命令运行,因为它都将在同一台服务器上,但有没有其他优化方法?

有趣

现在已经插入了大约 650,000 条记录,而且似乎已经趋于平稳。选择查询需要 60-70 秒,导入查询需要大约 170-180 秒,总处理时间为 230-250 秒。

【问题讨论】:

  • 不要将原则用于大型插入。使用 ORM 时会有很大的开销。如果您需要真正快速的批量插入,请执行 shell 脚本。
  • 我想我可以用直接的 SQL 编写整个事情,但我们假设出于某种任意原因,它必须通过教义来完成:D
  • 这是仅在一个表中插入行还是实体具有也需要添加的关系?如果它只有一个表,请通过数据库程序(如 MySql WorkBench 或类似的数据库类型)来完成。如果有相关实体,但您不会向其他表添加行,创建一个具有相同实体结构的新实体,不包括实体关系,并使用原则插入新行。这将提高插入时的速度,但不能在您的实际应用程序中用于其他任何事情。
  • 那么有另一个实体只使用整数作为相关字段的列类型,然后只获取 IDS 并插入这些?
  • 这似乎没什么区别。每次后续插入的时间仍在增加。

标签: php mysql symfony doctrine-orm innodb


【解决方案1】:

Doctrine 会跟踪您在工作单元中检索到的所有实体。每次刷新学说都会查找实体更改以确定要构造哪些INSERT 语句。当工作单元大小增长时,一切都会以指数方式放缓。 您必须在 entityManager 上调用 clear() 以从内存中删除不再需要的实体。见http://docs.doctrine-project.org/en/2.0.x/reference/batch-processing.html

$secondEm->transactional(function($em){
    foreach($results as $result){
        $value1 = $em->getRepository('A')->findOneBy(array('value'=>$result->getValue()));
        $value2 = $em->getRepository('B')->findOneBy(array('value'->$result->getValue()));
        $newEntity = new Entity();
        $newEntity->setValue1($value1)->setValue2($value2);
        $em->persist($newEntity);
    }
    $em->flush();
    $em->clear();
});

【讨论】:

  • 对不起,我在调用 clear,在事务之后,不会在删除事务中调用它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-26
  • 2014-05-15
  • 1970-01-01
  • 2017-12-04
  • 2021-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多