2

我正在使用带有 $modelName->find(...) 调用的 CakePHP 来选择相当多的行(可能是数百行)

通常,在 PHP/MySQL 中这当然不是问题,因为您在 while 循环中获取它们。但是,CakePHP 将所有行加载到一个耗尽内存限制的数组中。

有没有办法使用 $modelName->find(...) 构造但返回一个迭代器来按需获取每一行?

谢谢,大卫

4

11 回答 11

4

如果您的问题是由模型的关系引起的,您可以通过以下方式减少递归:

$模型名->递归=-1;

那么你只会得到当前模型的数据,没有任何关系。

遍历所有记录,您将能够以递归 > 0 再次查询它们的关系

于 2009-11-03T20:52:54.287 回答
4

这是可用于一次处理几行表的代码

    $limit = 10;
    $loop_no = 0;
    do {
        $handles = $this->SocialChannelHandle->find('all', array(
            'fields' => array('brand_id', 'handle'),
            'conditions' => array('social_channel_id' => $facebook['SocialChannel']['id']),
            'limit'  => $limit,
            'offset' => $limit * $loop_no,
            'order'  => 'id asc',
            'recursive' => -1)
        );
        $loop_no++;
    } while (count($handles) == $limit);
于 2012-12-08T20:51:04.153 回答
2

不,开箱即用的 Cake PHP(以及一般的 ActiveRecord)不支持迭代这样的结果集。如果您有一个实际需要表的所有记录的用例,那么使用原始 SQL 可能会更好。(或重新考虑您的用例)。

您也可以(并且可能已经考虑过)使用某种偏移量,并多次调用 ->find。如果您采用这种方法,请不要忘记按某个字段对结果集进行排序,以确保获得确定性的结果。当您关闭 ORDER BY 时,数据库似乎只返回已排序的行。我没有亲自尝试过,从多个查询的角度来看它似乎效率低下,但这是值得尝试的。

于 2009-02-11T22:51:43.293 回答
0

如果您使用存储过程来生成查询,那么模拟分页行为以一次获取查询段可能是一个好主意。在这种情况下,您将向存储过程发送两个额外参数,用于起始行索引和“page”-size,并返回调整 select 语句以仅检索 row_index + 1 和 row_index + page_size 之间的那些记录。

这都可以放入一个额外的循环层中,所以你得到一个新的段,然后在其中遍历该段中的每一行。

于 2009-02-11T21:43:41.397 回答
0

由于您的模型关系,您可能还会获得如此多的数据。对于您的 someModel->find() 调用,还有多少其他模型与 someModel 相关?

我在一个典型的共享托管服务器上使用了至少 1000 行的数组,没有内存问题。

更新:如果您不希望返回相关模型,您可以简单地使用 Containable 行为。因此,如果您尝试查找所有帖子但不想要评论,您可以使用 $this->Post->contain() 语法仅返回帖子记录。Containable 是必须使用 $actAs 参数添加到模型中的行为,$actAs = array('Containable');

于 2009-02-11T22:13:41.590 回答
0

我知道您正在寻找从查找条件返回的迭代器,但是如何使用带有可变偏移量的 LIMIT 子句(例如,您希望一次返回的行数)?这可能会带来一些并发问题,但如果您还包括 ORDER BY id 子句,您应该会在返回的行中看到一致的行为。然后,在您的循环中,只需重复发出 find(...) 查询。

这显然不是迭代器的优雅解决方案,但我想重复发出请求以返回更多行的开销将通过一次检索多行(在 Cake 中)与节省的成本相平衡.

最后,如果您真的在寻找性能,那么我认为 CakePHP 可能不是您的理想之选。随着新版本的发布,它的速度正在提高,但我相信它在性能方面仍然明显落后于其他框架。

于 2009-02-11T22:22:22.833 回答
0

我想这是不可能的,因为 CakePHP 正在动态构建一个表示您的数据库实体关系的多维数组。这应该在获取所有查询行之后完成,以便 CakePHP 知道所有可能的相关实体。

例子:

为了构建相应的多维数组,需要获取 3 行:

第1条
  |
  -- 评论 1
  |
  -- 评论 2
  |
  -- 评论 3

查询结果(1..n):

文章 | 评论
-----------------
1 | 1
-----------------
1 | 2
-----------------
1 | 3
于 2009-02-11T22:24:08.600 回答
0

您可以为查找请求添加限制。我现在没有时间写一个完整的答案。我稍后会更新它。

不,据我所知,当您在 mysql 或普通驱动程序中发出请求时。无论如何,它将返回您选择的所有元素。因此,如果您对内存限制有疑问,它可能在其他地方。您可以为一定数量的行添加限制。如果您的表有多个依赖项,但您不需要加载每个外键,则可以使用“包含”属性仅加载您需要的内容。

你能给我们描述一下你的桌子吗?以及您要选择的内容。

于 2009-02-16T20:14:41.697 回答
0

您可以使用递归参数(用于 Model#find 的 API)限制 find 方法调用,也可以即时取消绑定模型关联并减少检索的数据量(即时创建和销毁关联

于 2009-11-04T00:07:03.493 回答
0

已经有一段时间了,但是自从搜索中出现这个问题以来,我想提一下实际上有一种内置的方法可以做到这一点。就像是:

$page = 1;
$limit = 100;
while ($posts = $this->Post->find('all', array(
   'conditions' => ...,
   'page' => $page,
   'limit' => $limit,
   ...
))) {
    foreach ($posts as $post) {
        ...deal with one row...
    }
    $page++;
}

将通过数据集进行分页,尽管由于查询在每个 while 循环中重新执行,因此会带来一些性能损失。

(未测试)

于 2018-04-24T11:11:23.200 回答
-1

Ruby On rails 可以更好地处理这个问题。默认行为是不包含任何其他表,除非您使用 :include => :table_name 然后它会即时生成连接。

它没有理由不能做到这一点,只是没有。

于 2011-04-18T15:25:22.987 回答