从doctrine中的表中检索所有行

时间:2015-10-21 06:52:25

标签: php symfony doctrine-orm doctrine adodb-php

我有10万多行的表,我想在教条中选择所有这些,并对每一行执行一些操作,在symfony2中使用doctrine我尝试使用此查询:

    $query = $this->getDefaultEntityManager()
        ->getRepository('AppBundle:Contractor')
        ->createQueryBuilder('c')
        ->getQuery()->iterate();

    foreach ($query as $contractor) {
        // doing something
    }

然后我得到内存泄漏,因为我认为它在内存中写入了所有数据。

我在ADOdb中有更多经验,当我这样做时,在该库中:

$result = $ADOdbObject->Execute('SELECT * FROM contractors');
   while ($arrRow = $result->fetchRow()) {
        // do some action
   }

我没有任何内存泄漏。

那么如何从表中选择所有数据并且不会因为symfony2中的学说而导致内存泄漏?

  

问题编辑

当我尝试删除foreach并且只是迭代时,我也会出现内存泄漏:

$query = $this->getDefaultEntityManager()
            ->getRepository('AppBundle:Contractor')
            ->createQueryBuilder('c')
            ->getQuery()->iterate();

3 个答案:

答案 0 :(得分:6)

通常的做法是使用iterate()

$q = $this->getDefaultEntityManager()->createQuery('select u from AppBundle:Contractor c');
$iterableResult = $q->iterate();
foreach ($iterableResult as $row) {
    // do something
}

但是,正如学说文档所说,这仍然会导致错误。

  

数据库客户端/连接可以完全缓冲结果,分配PHP进程不可见的额外内存。对于大型套装,这可能很容易因为没有任何理由而终止这一过程。

最简单的方法是简单地创建具有偏移和限制的较小查询。

//get the count of the whole query first
$qb = $this->getDefaultEntityManager();
$qb->select('COUNT(u)')->from('AppBundle:Contractor', 'c');
$count = $qb->getQuery()->getSingleScalarResult();

//lets say we go in steps of 1000 to have no memory leak
$limit = 1000;
$offset = 0;

//loop every 1000 > create a query > loop the result > repeat
while ($offset < $count){
    $qb->select('u')
        ->from('AppBundle:Contractor', 'c')
        ->setMaxResults($limit)
        ->setFirstResult($offset);
    $result = $qb->getQuery()->getResult();
    foreach ($result as $contractor) {
        // do something
    }
    $offset += $limit;
}

对于这些繁重的数据集,这很可能会超过最长执行时间,默认情况下 30秒。因此,请务必在php.ini中手动更改 set_time_limit 。如果您只想更新具有已知模式的所有数据集,则应考虑编写一个大的更新查询,而不是在PHP中循环和编辑结果。

答案 1 :(得分:0)

尝试使用这种方法:

foreach ($query as $contractor) {
    // doing something

    $this->getDefaultEntityManager()->detach($contractor);
    $this->getDefaultEntityManager()->clear($contractor);
    unset($contractor); // tell to the gc the object is not in use anymore

}

希望这个帮助

答案 2 :(得分:0)

如果您确实需要获取所有记录,我建议您直接使用database_connection。查看其界面并选择不会将所有数据加载到内存中的方法(并且不会将记录映射到您的实体)。

你可以使用这样的东西(假设这段代码在控制器中):

$db = $this->get('database_connection');
$query = 'select * from <your_table>';
$sth = $db->prepare($query);
$sth->execute();
while($row = $sth->fetch()) {
    // some stuff
}

可能它不是您需要的,因为您可能希望在处理完所有集合后拥有对象。但也许你不需要这些物品。无论如何想想这个。