私のsymfony2コマンドでは、何十万ものURLを(文字列として)ドキュメントに挿入するスクリプトを実行しています。
これが私が使用している2つのドキュメントの基本構造です。プログラムが実行される前に、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秒あたり1回の書き込みが遅くなり、コードが非常に無効になります。
この問題を修正する最初の試みは、を使用してフラッシュした直後にドキュメントマネージャーをクリアすることでしたが、$dm->clear();
これは、ドキュメントマネージャーが現在のParentDocumentを追跡できなくなることを意味しました。だから私の解決策はこれでした:
$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();
}
これで問題は解決しました。プログラムの実行全体を通して書き込み速度は一貫して速く、数百万行を徐々に遅らせることなく挿入することができました。
ただし、これは悪い習慣であり、迅速な修正ハックのように感じます。読み取り/書き込み速度を遅くすることなく、ドキュメントマネージャーを使用してSymfony2に数百万行を挿入するためのベストプラクティスは何ですか?