当我试图从供应商那里获取元数据时,我正在将数据转换为我们自己的元数据格式。但是由于导入数据的绝对大小,应用程序将获得OutOfMemoryException。
我尝试了几件事。就像增加可能使用的内存一样,我也尝试使用Doctrine Batch Processing,但是这种方法存在一个小问题。原则数据处理基于带有索引的“ for”循环。
$batchSize = 20;
for ($i = 1; $i <= 10000; ++$i) {
$user = new CmsUser;
$user->setStatus('user');
$user->setUsername('user' . $i);
$user->setName('Mr.Smith-' . $i);
$em->persist($user);
if (($i % $batchSize) === 0) {
$em->flush();
$em->clear(); // Detaches all objects from Doctrine!
}
}
$em->flush(); //Persist objects that did not make up an entire batch
$em->clear();
但是我导入的数据是我在三维“ foreach”循环中创建的多层数组:
$this->index = 0;
$batchSize = 100;
foreach ($response as $item) {
$item = new Item;
$item->setName($item->name);
$item->setStatus($item->status);
$em->persist($item);
if (($this->index % $batchSize) === 0) {
$em->flush();
$em->clear();
}
foreach ($item->category as $category) {
$category = new Category;
$category->setName($category->name);
$category->setStatus($category->status);
$em->persist($item);
if (($this->index % $batchSize) === 0) {
$em->flush();
$em->clear();
}
foreach ($category->suppliers as $supplier) {
$supplier = new Supplier;
$supplier->setName($supplier->name);
$supplier->setStatus($supplier->status);
$em->persist($item);
if (($this->index % $batchSize) === 0) {
$em->flush();
$em->clear();
}
}
}
}
$this->em->flush();
这是虚构的代码,用来说明我的问题。有了这个,应用程序仍然会出现OutOfMemoryException异常,我确实感觉到批处理方法无法正常工作。
我想降低内存使用率,以便应用程序正常运行,或者想要一些建议以尝试找到解决此问题的其他方法。就像进行后台处理一样,只需要在后台进行导入即可。
答案 0 :(得分:0)
编写嵌套foreach
循环的方式显然会成倍地消耗资源。我还怀疑它无法实现您真正想要的功能,因为您会有很多重复的Supplier
和Category
。
在理论上使用完整实体也会带来大量开销,但是它确实具有一些优势,因此我假设您要这么做。
我对这样的大宗进口商品采取的方法是从下至上进行工作。在您的情况下,它可能是我下面的内容的变体。假定您在现有数据库中有数据,并且旧数据库中的每个现有“实体”将具有其自己唯一的id
。
1-将所有供应商从旧数据库导入新数据库;新数据库中有一个名为oldId
的列,该列引用了旧数据库中的唯一id
。停止以清除缓存/内存。
2-将所有供应商从新数据库中拉入以其oldId
索引的数组。我使用如下代码:
$suppliers = [];
$_suppliers = $this->em->getRepository(Supplier:class)->findAll();
foreach ($_suppliers as $supplier) {
$suppliers[$supplier->getOldId()] = $supplier;
}
3-对类别重复步骤1。在导入期间,您的旧数据库将引用链接的供应商的oldId
。尽管您的代码没有执行此操作,但是我假设您想维护供应商与类别之间的链接,因此您现在可以在链接的“旧”供应商上的循环中按其oldId
来引用供应商:
$category->addSupplier($suppliers[ <<oldSupplier Id>> ]);
4-对单个项目重复上述操作,只有这次保存链接的类别。
很明显,有很多调整可以改善这一点。主要要点是,一次接触每个供应商,一次接触每个类别,然后依次接触每个项目一次,比尝试在一个深层嵌套的循环中处理要快几个数量级,而且资源消耗更少。