Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Symfony2中mongodb批量插入的最佳实践_Mongodb_Symfony_Doctrine_Doctrine Orm_Symfony 2.1 - Fatal编程技术网

Symfony2中mongodb批量插入的最佳实践

Symfony2中mongodb批量插入的最佳实践,mongodb,symfony,doctrine,doctrine-orm,symfony-2.1,Mongodb,Symfony,Doctrine,Doctrine Orm,Symfony 2.1,在我的symfony2命令中,我正在运行一个脚本,该脚本将数十万个URL(作为字符串)插入到文档中 下面是我正在使用的两个文档的基本结构。在程序运行之前,mongodb中已有数千个ParentDocuments,但没有ChildDocuments: ParentDocument: $id:id $subDocument:OneToManyReference(ChildDocument) $etc:everythingelse ChildDocument: $id

在我的symfony2命令中,我正在运行一个脚本,该脚本将数十万个URL(作为字符串)插入到文档中

下面是我正在使用的两个文档的基本结构。在程序运行之前,mongodb中已有数千个ParentDocuments,但没有ChildDocuments:

ParentDocument:
    $id:id
    $subDocument:OneToManyReference(ChildDocument)
    $etc:everythingelse

ChildDocument:
    $id:id
    $url:string
    $parentDocument:ManyToOneReference(ParentDocument)
和我的命令代码:

$dm = $this->getContainer()->get('doctrine_mongodb.odm.document_manager');
$parentDocuments = $dm->repository('My:Bundle:ParentDocument')->findAll();
while ($parentDocument = $parentDocuments->getNext()) {
    //Returns an array of hundreds of thousands urls
    $urls = $this->somehowFetchUrlsRelatedToTheParentDocument($parentDocument);
    foreach ($urls as $url) {
        $subDocument = new SubDocument();
        $subDocument->setUrl($url);
        $subDocument->setParentDocument($parentDocument);
        $dm->persist($subDocument);
    }
    $dm->flush();
}
当我运行这个简单的命令时,一开始的写入速度非常快。但是,在插入数百万行的情况下,写入速度会显著降低。在命令运行10分钟后,速度慢到每秒写入1次,使代码极为无效

我修复此问题的第一次尝试是在文档管理器刷新后立即使用
$dm->clear()清除它
但这意味着文档管理器将无法跟踪当前的父文档。所以我的解决方案是:

$dm = $this->getContainer()->get('doctrine_mongodb.odm.document_manager');
$parentDocumentCursors = $dm->repository('My:Bundle:ParentDocument')->findAll();
$parentDocuments = array();
while ($parentDocument = $parentDocumentCursors->getNext()) {
    array_push($parentDocuments, $parentDocument);
}
$dm->clear();
unset($dm);
$dm = $this->getContainer()->get('doctrine_mongodb.odm.document_manager');
foreach ($parentDocuments as $parentDocument) {
    $urls = $this->somehowFetchUrlsRelatedToTheParentDocument($parentDocument);
    foreach ($urls as $url) {
        $subDocument = new SubDocument();
        $subDocument->setUrl($url);
        $subDocument->setParentDocument($parentDocument);
        $dm->persist($subDocument);
    }
    $dm->flush();
    $dm->clear();
}
这就解决了问题。在整个程序执行过程中,写入速度始终很快,并且能够在不逐渐延迟的情况下插入数百万行


然而,这感觉像是一个糟糕的做法和一个快速修复黑客。使用document manager在Symfony2中插入数百万行而不会使读/写速度变慢的最佳做法是什么?

我会避免使用Symfony的document manager,而直接使用batchInsert()函数。这里的文档中描述了这一点,我觉得Doctrine的ODM实际上在伤害您。

我会避免使用Symfony的文档管理器,而直接使用batchInsert()函数。文档中描述了这一点,我觉得Doctrine的ODM实际上伤害了您。

为了在Doctrine中进行批量插入,您需要将刷新移到循环之外。考虑下面的场景,在这里您将坚持FrAACH,然后在完成FACH时刷新。唯一的问题是,在刷新之前,您将无法查询批中插入的任何数据

$dm = $this->getContainer()->get('doctrine_mongodb.odm.document_manager');
foreach ($parentDocuments as $parentDocument) {
    $urls = $this->somehowFetchUrlsRelatedToTheParentDocument($parentDocument);
    foreach ($urls as $url) {
        $subDocument = new SubDocument();
        $subDocument->setUrl($url);
        $subDocument->setParentDocument($parentDocument);
        $dm->persist($subDocument);
    }    
 }
$dm->flush();
$dm->clear();
另一个选项是执行push、pushall或addto设置。 要考虑的一个问题是,需要在PHP中使用STDC类以添加对象。 我发现这是更新子文档的最快方法。 例如:

$dm->createQueryBuilder('My:Bundle:ParentDocument')
    ->update()
    ->field('subDocument')->push( (object) array('url'=> $url) )
    ->field('id')->equals( $parentDocumentId )
    ->getQuery()
    ->execute();

为了在doctrine中进行批量插入,您需要将刷新移到循环之外。考虑下面的场景,在这里您将坚持FrAACH,然后在完成FACH时刷新。唯一的问题是,在刷新之前,您将无法查询批中插入的任何数据

$dm = $this->getContainer()->get('doctrine_mongodb.odm.document_manager');
foreach ($parentDocuments as $parentDocument) {
    $urls = $this->somehowFetchUrlsRelatedToTheParentDocument($parentDocument);
    foreach ($urls as $url) {
        $subDocument = new SubDocument();
        $subDocument->setUrl($url);
        $subDocument->setParentDocument($parentDocument);
        $dm->persist($subDocument);
    }    
 }
$dm->flush();
$dm->clear();
另一个选项是执行push、pushall或addto设置。 要考虑的一个问题是,需要在PHP中使用STDC类以添加对象。 我发现这是更新子文档的最快方法。 例如:

$dm->createQueryBuilder('My:Bundle:ParentDocument')
    ->update()
    ->field('subDocument')->push( (object) array('url'=> $url) )
    ->field('id')->equals( $parentDocumentId )
    ->getQuery()
    ->execute();