Вы правильно предположили, что нужен итератор. В PHP есть такая штука, как генератор, одна из разновидностей.
Вот, если использовать его, то можно в принципе попробовать уложиться в лимит по памяти.
На своих проектах для полного прохода по записям в БД использую, что-то типа такого:
public function getEntitiesByBatch(int $limit): \Generator
{
$expr = $this->createQueryBuilder('s');
$predicates = $expr->expr()->andX();
$predicates->add($expr->expr()->isNotNull('s.field1'));
$predicates->add($expr->expr()->isNotNull('s.field2'));
$accountState = $expr->expr()->eq('a.field3', 'true');
$qb = $this->createQueryBuilder('s')
->where($predicates)
->join('s.account', 'a')
->where($accountState)
;
$batches = ceil($qb->select('count(s.id)')->getQuery()->getSingleScalarResult() / $limit);
for ($batch = 1; $batch <= $batches; ++$batch) {
yield $this->createQueryBuilder('s')
->where($predicates)
->join('s.account', 'a')
->where($accountState)
->setFirstResult($batch * $limit - $limit)
->setMaxResults($limit)
->getQuery()
->toIterable() // тут можно возращать просто массив, но мне нужен итерируемый объект
;
}
}
Upd 1 А сорян, у вас тут битрикс, может у него есть какие-то дефолтные способы хз. Но общий смысл генераторов от этого не сильно меняется:)
Upd 2 И да, этот код работает в консольном скрипте.