CakePHP建议迭代一个巨大的表并生成一个站点地图?

时间:2010-03-03 06:34:09

标签: php performance cakephp sitemap

我正在尝试使用CakePHP创建一个XML站点地图,此表目前有超过50,000条记录,每条记录等同于站点地图中的URI。现在我面临的问题是CakePHP在生成它时会让我失去内存,原因有两个:

  1. find('all')正在构建一整套50,000个URI的巨大关联数组。
  2. 由于我不想从控制器本身输出HTML,我正在将包含URI,优先级,更改频率等的关联数组传输到带有$this->set()调用的视图 - 这也是巨大的,包含50,000个指数。
  3. 是否有可能在遵循MVC和CakePHP指南的同时执行此操作?

6 个答案:

答案 0 :(得分:4)

我知道这个问题已经过时了,但对于非常大的问题,我认为仍然没有好的解决方案。

要遍历一个巨大的结果集,您可以使用DboSource方法。

首先获得DBO

$dbo = $this->Model->getDataSource();

构建查询

$sql = $dbo->buildStatement($options);

然后执行语句并遍历结果

if ($dbo->execute($sql))
{
    while ($dbo->hasResult() && $row = $dbo->fetchResult()) {
        // $row is an array with same structure like find('first')
    }
}

答案 1 :(得分:3)

本周我遇到了类似的问题,偶然发现了Containable行为。这允许您减少任何与关系相关的查询(如果有的话)。

最好的解决方案是以编程方式使用LIMIT and OFFSET,并一次循环记录集小块。这样可以避免一次将50K记录填入内存。

答案 2 :(得分:2)

find('all')过于贪婪,如果你不想耗尽内存,你必须更加具体。

如上所述,使用Containable行为。如果您只需要表中的结果(没有关联的表),并且只需要几个字段,那么更明确的查询应该更好:

$results = $this->YourModel->find('all', array(
    'contain' => false,
    'fields' => array('YourModel.name', 'YourModel.url')
);

您还应该考虑添加一个html缓存机制(cakePHP有内置或使用suggested by Matt Curry)。

当然它将是一个缓存版本,并且不会完美地更新到您的列表中。如果你想要更多的控制,你总是可以将结果保存在蛋糕缓存中(使用Cache::write),使用模型的afterSave / afterDelete回调更新缓存的值并从此处重新创建缓存的xml文件。

答案 3 :(得分:2)

你确定你必须在50.000条记录上耗尽内存吗?即使一行的大小为1K(相当大),你还需要处理大约50 MB的数据?我的P1有足够的RAM来处理它。将php.ini中的memory_limit设置为高于默认值。 (还要考虑调整max_execution_time。)

另一方面,如果您认为数据集太大并且将其处理为资源过于密集,那么您不应该动态地提供该页面,这是完美的DDoS诱饵。 (至少我会大量缓存它。) 您可以安排一个cron作业,每隔X小时由一个服务器端脚本重新生成页面,而不受MVC惩罚,即一次性向视图提供所有数据,它可以顺序处理行。

答案 4 :(得分:1)

您是否尝试过unBindModel(如果您有关系)......

每当我必须在cakephp中进行大量查询时,我只需使用“常规”mysql函数,如mysql_query,mysql_fetch_assoc等。更快,更不缺乏内存...

答案 5 :(得分:1)

使用https://github.com/jamiemill/cakephp_find_batch或自己实施此逻辑。