CakePHP推荐的方法来遍历一个大表并生成网站地图?

6
我正在试图使用CakePHP创建XML网站地图,从一个当前有超过50,000条记录的表中生成,每个记录都相当于网站地图中的一个URI。现在我遇到的问题是,当生成时,由于两个原因,CakePHP会耗尽我的内存:
1. `find('all')`正在构建一个包含所有50,000个URI的巨大关联数组。 2. 由于我不想从控制器本身输出HTML,因此我使用`$this->set()`将包含URI、优先级、更改频率等信息的关联数组传递到视图--这也是巨大的,包含50,000个索引。
有没有可能在遵循MVC和CakePHP指南的情况下完成这项工作?
6个回答

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')
    }
}

从CakePHP 2.4.4开始,$dbo->buildStatement需要两个参数。此外,$dbo->buildStatement仅在没有表名的情况下返回无效的SQL。在查看源代码后,我使用了$this->generateAssociationQuery($model, null, null, null, null, $queryData, false, $null);代替。 - VCD

3
我上周遇到了类似的问题,并偶然发现了Containable行为。如果您有任何与关系相关的查询,这将帮助您缩减查询结果。
最好的解决方案是通过编程使用LIMIT和OFFSET,并逐个小块地循环记录集。这样可以避免一次将50K条记录塞入内存中。

谢谢回复。我没有任何相关的表格,这个查询或多或少是一个简单的SELECT操作。我想避免发出多个查询。此外,即使我这样做了,我如何将数据传输到视图? - Alex J
你会在同一个视图中显示所有的50k条记录吗?如果不是,大多数分页模式都可以很好地与limit/offset查询配合使用。如果您确实必须一次性显示它们所有,请查看您的php.ini(如果您有服务器管理访问权限)并将memory_limit更改为更高的值。这可能会解决使用find('all')时的内存问题。如果您的表具有许多字段,请使用“fields”值来缩小必要的范围(如另一条评论中所述)。 - bojo

2

find('all')过于贪婪,如果您不想耗尽内存,您需要更具体地指定查询条件。

如上所述,请使用Containable行为。如果您只需要来自您的表的结果(不包括关联表)并且仅需要几个字段,那么像这样更明确的查询应该更好:

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

您还应考虑添加一个html缓存机制(cakePHP有内置的缓存机制,或者使用Matt Curry建议的)。

当然,这将是一个缓存版本,不会完全更新您的列表。如果您想要更多控制,您可以始终将结果保存在cake缓存中(使用Cache::write),使用您模型的afterSave / afterDelete回调来更新缓存值并从此重新创建缓存xml文件。


具体来说,请查看“fields”参数以查找()函数。 - Travis Leleu

2
你确定需要在50,000条记录上耗尽内存吗?即使一行的大小为1K(相当巨大),你也只需要处理大约50MB的数据?我的P1有足够的RAM来处理这个。将php.ini中的memory_limit设置得比默认值更高。(还要考虑调整max_execution_time。)
另一方面,如果你认为数据集太大,处理它会消耗过多资源,那么你不应该动态地提供该页面,它是完美的DDoS诱饵。(至少我会大量缓存它。)你可以安排一个cron job通过一个服务器端脚本定期地每隔X小时重新生成页面,该脚本不会因为一次性向视图服务所有数据而遭受MVC惩罚,而是可以按顺序逐行处理数据。

网站地图在我的本地开发环境中完全正常。一旦我部署到共享托管上,由于内存非常有限,它就会崩溃。这正是我所想的,只是想再次确认并确保我正在走这条路,因为没有CakePHP/MVC选项了。谢谢! - Alex J

1

你尝试过使用unBindModel(如果你有关联)吗?...

每当我在cakephp中需要执行大量查询时,我只是使用“常规”的mysql函数,如mysql_query、mysql_fetch_assoc等。速度更快,而且没有内存不足的问题...


这是一个单表查询。看起来老派的MySQL是高效且唯一的选择,但那时我已经远离CakePHP了。而且我仍然面临如何呈现计算出的关联数组的问题。 - Alex J

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接