我正在尝试使用CakePHP创建一个XML站点地图,此表目前有超过50,000条记录,每条记录等同于站点地图中的URI。现在我面临的问题是CakePHP在生成它时会让我失去内存,原因有两个:
find('all')
正在构建一整套50,000个URI的巨大关联数组。 $this->set()
调用的视图 - 这也是巨大的,包含50,000个指数。是否有可能在遵循MVC和CakePHP指南的同时执行此操作?
答案 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)