是否可以在本地使用分页对Magento集合进行迭代?


21

我的意思是-有没有办法做:

$collection = $model->getCollection();
foreach ($collection as $item) { 
    $item->doStuff();
}

这样,即使集合有10万行,它一次也只能从MySQL加载一行页面,并在后台为您神奇地分页。

从看来,Varien_Data_Collection_Db::load()这似乎是不可能的,而只是想检查一下。这似乎应该是一个普遍需要。

Answers:


18

你真的应该用

Mage::getSingleton('core/resource_iterator')

为此,它的存在纯粹是出于您提到的性能原因。

否则,您可以在循环中使用稍微不太优雅的解决方案setPageSize-这里有一个很好的例子,https://stackoverflow.com/questions/3786826/how-to-loop-a-magento-collection


1
先生,是一位绅士和学者。
kalenjordan

+1是setPageSize因为它是语义。
philwinkle

我意识到的另一件事是该core/resource_iterator解决方案实际上并未对mysql查询进行分页。它一次加载了整个结果集,但是随后一次给您一行以处理您的PHP代码。因此,它确实避免了PHP内部的内存错误,但是如果结果集很大,则在某些时候它将触发mysql max数据包大小。我认为我将尝试使用setPageSize()
kalenjordan

是的,我有点忽略了追求点!它的真正目的是针对单一产品加载而不是分页收集。但是它应该作为基础。
Ben Lessani-Sonassi

我实现了一个通用的批处理迭代器,该迭代器将查询批处理到MySQL,还提供了一个单独的集合项回调。好奇您的想法:gist.github.com/kalenjordan/5483065
kalenjordan

5

我同意Ben Lessani的观点,如果可能的话,应该使用core/iterator资源模型一次加载大集合。

但是,有局限性。如“ addAttributeToSelect不能与core / resource_iterator一起使用? ”中所述,如果需要包括属性值表中的值,则它不适用于EAV模型。

而且,来自StackOverflow的链接示例实际上并不是那么好,因为它使用不同的LIMIT表达式重复了相同的查询。对于复杂的查询,这可能是性能问题,但更重要的是,如果在两者之间添加新行,则会得到重复。

处理大块集合的更好方法是先加载所有ID,然后将这些ID用作实际分页集合的过滤器。

产品的简单示例:

$ids = Mage::getModel('catalog/product')
    ->getCollection()
    ->getAllIds();

$page = 1;
do {
    $collection = Mage::getModel('catalog/product')
        ->getCollection()
        ->addIdFilter($ids)
        ->setPageSize(100)
        ->setCurPage($page);

    $results = $collection->load();

    // do stuff ......

    $page++;

} while ($results->count());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.