【问题标题】:How to get one line at a time from eloquent query in laravel?如何从laravel中的雄辩查询中一次获取一行?
【发布时间】:2014-05-15 00:30:15
【问题描述】:

假设我有一个简单的查询来获取表中的所有行:

App::make('My_Model')->get();

但是,我有大量的行——比如 100,000 行,如此之多以至于 PHP 试图将它们全部读入时内存不足。

出于某种原因,我想遍历这些行中的每一行,并根据它们进行一些操作。

有没有办法告诉 laravel 一次给我一行,就像旧的 mysql_fetch_row 的工作方式一样?

注意:我目前正在解决这个问题,方法是使用 limit() 命令一次获取 5000 行,效果很好,只是它重复查询 20 次。

我想知道 laravel 或 eloquent 中是否有任何内置方法可以给我下一行,而不是所有行?

【问题讨论】:

    标签: php sql laravel-4 eloquent


    【解决方案1】:

    问题是,应用程序的下一行是什么?除非您正在构建一个具有光标的命令行应用程序,否则您的应用程序只为请求而存在。 Laravel 可以为您提供获取光标子集的方法,因此如果您需要 5000 行,则可以同时获取这 5000 行。

    所以你可以使用分页:

    $someUsers = User::where('votes', '>', 100)->paginate(5000);
    

    采取并跳过:

    $page = 5;
    
    $pageSize = 5000;
    
    $users = User::skip($page * $pageSize)->take($pageSize)->get();
    

    Chunk,内部使用分页,但它有点限制,因为它会强制你处理整个光标:

    User::chunk(5000, function($users)
    {
        /// every time this clojure is ran you get a new subset of 5000 rows.
    
        foreach ($users as $user)
        {
            // do whatever you need with them
        }
    });
    

    旁注:您可以通过关闭查询日志来节省内存:

    DB::disableQueryLog();
    

    【讨论】:

      【解决方案2】:

      如果你想一次处理一千个,Eloquent 中的 chunk() 方法应该适合你:

      My_Model::chunk(1000, function($my_models)
      {
          foreach ($my_models as $my_model)
          {
              // do something
          }
      });
      

      更多内容请关注Eloquent docs

      取决于您对数据执行的操作...

      【讨论】:

        【解决方案3】:

        您要执行什么样的操作?您描述的方式是将所有 100,000 条记录加载到活动内存中,但几乎没有理由需要这样做,除非您真的想要显示所有 100,000 条记录。

        • 如果您想更改部分但不是全部记录,应该可以构建一个 DB::update() 查询来执行此操作,因此您根本不需要将记录加载到 PHP 的内存中李>
        • 如果您只想显示某些记录,应该可以修改您的 $model 查询,以便只将记录加载到您实际需要的 PHP 内存中。
        • 如果您需要实际显示整个记录集,那么您实际上需要逐个迭代它们,但这听起来不像您想要做的。

        向我们提供更多信息,您实际上想要完成什么?

        【讨论】:

        • 我正在尝试逐个迭代它们。如果不将整个内容加载到内存中,我找不到用于迭代查询结果的 laravel 方法,这就是我要问的问题。
        • 我只是想了解>为什么
        • 用例示例:生成 csv 文件、发送到邮件列表、统计分析......有很多。你是对的,任何可能成为目标的事情都可以更容易地以另一种方式完成,但有时实施选择可以由不懂技术的老板做出,我们可怜的开发人员只需要尽我们所能处理它。
        • 好的,我现在明白你的意思了,尤其是 CSV 文件的情况。困难在于您本质上是在问“我如何发出单个 SQL 查询但让 SQL 服务器将结果保存在内存中,以便我可以遍历它们而不将整个结果集加载到 PHP 中?”我怀疑这是可能的,但它肯定看起来不像是 Laravel 开箱即用的东西。我认为您使用的一次 5000 条记录的方法是您最好的选择。
        • 核心 php 函数可以做到这一点 - 例如mysql_fetch_assoc 仅加载单行,因此 mysql_fetch_assoc 上的循环将允许处理任意数量的行而不会耗尽内存。但是,现在已弃用,因此我需要使用 ORM。
        【解决方案4】:

        对于使用 Laravel 5.2+ 登陆这里的任何人(就像我一样)现在有一个可用的“光标”方法返回一个生成器

        https://laravel.com/api/5.2/Illuminate/Database/Query/Builder.html#method_cursor

        所以代替 ->get() 使用 ->cursor()

        【讨论】:

        • 只是为了进一步澄清这一点,::cursor() 是 Builder 方法,而不是 Model 方法。要使用游标从表中获取每一行,您的代码应如下所示:foreach (MyModel::query()->cursor() as $stdClass) { /* do something */ }。请注意,您不会在此处获得 MyModel 对象;而是你会得到\StdClass 的实例。
        猜你喜欢
        • 2016-02-14
        • 2018-01-26
        • 2021-07-23
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-11
        相关资源
        最近更新 更多