Laravel-收集关系需要花费大量时间

Laravel-收集关系需要花费大量时间,laravel,laravel-5.4,lumen,lumen-5.4,Laravel,Laravel 5.4,Lumen,Lumen 5.4,我们正在开发一种带有流明的API。 今天,我们在获取“TimeLog”模型集合时遇到了一个困惑的问题。 我们只是想从board模型和task模型中获取所有时间日志和附加信息。 在一行时间日志中,我们有一个board_id和一个task_id。这两者都是1:1的关系 这是我们获取全部数据的第一个代码。这花费了很多时间,有时我们会超时: BillingController.php public function byYear() { $timeLog = TimeLog::get()

我们正在开发一种带有流明的API。 今天,我们在获取“TimeLog”模型集合时遇到了一个困惑的问题。 我们只是想从board模型和task模型中获取所有时间日志和附加信息。 在一行时间日志中,我们有一个board_id和一个task_id。这两者都是1:1的关系

这是我们获取全部数据的第一个代码。这花费了很多时间,有时我们会超时: BillingController.php

public function byYear() {

       $timeLog = TimeLog::get(); 

        $resp = array(); 

        foreach($timeLog->toArray() as $key => $value) {  

            if(($timeLog[$key]->board_id && $timeLog[$key]->task_id) > 0 ) {      

                 array_push($resp, array(
                    'board_title' => isset($timeLog[$key]->board->title) ? $timeLog[$key]->board->title : null,
                    'task_title' => isset($timeLog[$key]->task->title) ? $timeLog[$key]->task->title : null,
                    'id' => $timeLog[$key]->id
                )); 
            }
        }


        return response()->json($resp);
    }   
 public function byYear() {



            $timeLog = TimeLog::
join('oc_boards', 'oc_boards.id', '=', 'oc_time_logs.board_id')
                            ->join('oc_tasks', 'oc_tasks.id', '=', 'oc_time_logs.task_id')
                            ->join('oc_users', 'oc_users.id', '=', 'oc_time_logs.user_id')
                            ->select('oc_boards.title AS board_title', 'oc_tasks.title AS task_title','oc_time_logs.id','oc_time_logs.time_used_sec','oc_users.id AS user_id')
                            ->getQuery()
                            ->get(); 

            return response()->json($timeLog);
        }   
建立关系的TimeLog.php

public function board()
        {
            return $this->belongsTo('App\Board', 'board_id',  'id');
        }

        public function task()
        {
            return $this->belongsTo('App\Task', 'task_id',  'id');
        }
我们的新方式是这样的: BillingController.php

public function byYear() {

       $timeLog = TimeLog::get(); 

        $resp = array(); 

        foreach($timeLog->toArray() as $key => $value) {  

            if(($timeLog[$key]->board_id && $timeLog[$key]->task_id) > 0 ) {      

                 array_push($resp, array(
                    'board_title' => isset($timeLog[$key]->board->title) ? $timeLog[$key]->board->title : null,
                    'task_title' => isset($timeLog[$key]->task->title) ? $timeLog[$key]->task->title : null,
                    'id' => $timeLog[$key]->id
                )); 
            }
        }


        return response()->json($resp);
    }   
 public function byYear() {



            $timeLog = TimeLog::
join('oc_boards', 'oc_boards.id', '=', 'oc_time_logs.board_id')
                            ->join('oc_tasks', 'oc_tasks.id', '=', 'oc_time_logs.task_id')
                            ->join('oc_users', 'oc_users.id', '=', 'oc_time_logs.user_id')
                            ->select('oc_boards.title AS board_title', 'oc_tasks.title AS task_title','oc_time_logs.id','oc_time_logs.time_used_sec','oc_users.id AS user_id')
                            ->getQuery()
                            ->get(); 

            return response()->json($timeLog);
        }   
我们删除了TimeLog.php中的关系,因为我们不再需要它了。现在我们有大约1秒的加载时间,这很好! 时间日志表中大约有20k个条目

我的问题是:

  • 为什么第一个方法超出范围(是什么导致超时?)
  • 什么是getQuery();你到底是怎么做的

  • 如果你需要更多的信息,就问我

    我也遇到过类似的问题。这里的主要问题是,Elloquent执行大量任务的速度非常慢,因为它会同时获取所有结果,因此简单的答案是使用PDO fetch逐行获取它

    简短示例:

    $db = DB::connection()->getPdo();
    
    $query_sql = TimeLog::join('oc_boards', 'oc_boards.id', '=', 'oc_time_logs.board_id')
                                ->join('oc_tasks', 'oc_tasks.id', '=', 'oc_time_logs.task_id')
                                ->join('oc_users', 'oc_users.id', '=', 'oc_time_logs.user_id')
                                ->select('oc_boards.title AS board_title', 'oc_tasks.title AS task_title','oc_time_logs.id','oc_time_logs.time_used_sec','oc_users.id AS user_id')
                                ->toSql();
    
    $query = $db->prepare($query->sql);
    $query->execute();
    $logs = array();
     while ($log = $query->fetch()) {
       $log_filled = new TimeLog();
       //fill your model and push it into an array to parse it to json in future
       array_push($logs,$log_filled);
    }
    return response()->json($logs);
    

    我也遇到过类似的问题。这里的主要问题是,Elloquent执行大量任务的速度非常慢,因为它会同时获取所有结果,因此简单的答案是使用PDO fetch逐行获取它

    简短示例:

    $db = DB::connection()->getPdo();
    
    $query_sql = TimeLog::join('oc_boards', 'oc_boards.id', '=', 'oc_time_logs.board_id')
                                ->join('oc_tasks', 'oc_tasks.id', '=', 'oc_time_logs.task_id')
                                ->join('oc_users', 'oc_users.id', '=', 'oc_time_logs.user_id')
                                ->select('oc_boards.title AS board_title', 'oc_tasks.title AS task_title','oc_time_logs.id','oc_time_logs.time_used_sec','oc_users.id AS user_id')
                                ->toSql();
    
    $query = $db->prepare($query->sql);
    $query->execute();
    $logs = array();
     while ($log = $query->fetch()) {
       $log_filled = new TimeLog();
       //fill your model and push it into an array to parse it to json in future
       array_push($logs,$log_filled);
    }
    return response()->json($logs);
    
    --第一个问题--

    您可能面临的一个问题是内存中存在大量数据,即:

    $timeLog = TimeLog::get();
    
    这已经是巨大的。然后,当您尝试将集合转换为数组时:

  • 在集合中有一个循环
  • 根据我的理解,在初始化循环时使用
    $timeLog->toArray()
    效率不高(不过我可能对此并不完全正确)
  • 为了检索相关模型,进行了数千次查询
  • 因此,我建议使用五种方法(其中一种方法可以避免数百次查询),最后一种方法可以高效地返回自定义结果:

  • 由于您有许多数据,因此
    chunk
    结果ref:因此您有以下内容:

    $timeLog = TimeLog::chunk(1000, function($logs){
        foreach ($logs as $log) {
        // Do the stuff here
        }
    }); 
    
  • 另一种方法是使用游标(在条件匹配的地方只运行一个查询),可以理解为游标的内部操作正在使用

  • 这看起来像第一个问题,但是您已经将查询范围缩小到您需要的范围:

    TimeLog::where([['board_id','>',0],['task_id', '>', 0]])->get()
    
  • 已经可以动态显示所需的关系,但也可能会在内存中产生更多数据。因此,chunk方法可能会使事情更易于管理(即使您希望加载相关模型)

  • 你可以简单地使用

    • 使用transformer,您可以以优雅、干净和更可控的方式加载相关模型,即使大小巨大,一个更大的好处是您可以转换结果,而不必担心如何循环 您可以简单地引用,以便对其进行简单的使用。然而,如果你不需要改变你的反应,那么你可以采取其他的选择
  • 虽然这可能不能完全解决问题,但因为您面临的主要问题是基于内存管理的,所以上述方法应该是有用的

    --第二个问题--

    基于Laravel API,您可以看到:

    它只返回底层查询生成器实例。据我观察,根据你的例子,这是不必要的

    更新

    对于问题1,由于您似乎只想将结果作为响应返回,所以老实说,对该结果进行分页更有效。其中最简单的是简单的,这是好的。唯一的问题是它对数据库进行了一些查询,但是检查最后一个索引;我猜它也使用了
    光标
    ,但不确定。最后,我想这可能更理想,因为:

    return TimeLog::paginate(1000);
    
    --第一个问题--

    您可能面临的一个问题是内存中存在大量数据,即:

    $timeLog = TimeLog::get();
    
    这已经是巨大的。然后,当您尝试将集合转换为数组时:

  • 在集合中有一个循环
  • 根据我的理解,在初始化循环时使用
    $timeLog->toArray()
    效率不高(不过我可能对此并不完全正确)
  • 为了检索相关模型,进行了数千次查询
  • 因此,我建议使用五种方法(其中一种方法可以避免数百次查询),最后一种方法可以高效地返回自定义结果:

  • 由于您有许多数据,因此
    chunk
    结果ref:因此您有以下内容:

    $timeLog = TimeLog::chunk(1000, function($logs){
        foreach ($logs as $log) {
        // Do the stuff here
        }
    }); 
    
  • 另一种方法是使用游标(在条件匹配的地方只运行一个查询),可以理解为游标的内部操作正在使用

  • 这看起来像第一个问题,但是您已经将查询范围缩小到您需要的范围:

    TimeLog::where([['board_id','>',0],['task_id', '>', 0]])->get()
    
  • 已经可以动态显示所需的关系,但也可能会在内存中产生更多数据。因此,chunk方法可能会使事情更易于管理(即使您希望加载相关模型)

  • 你可以简单地使用

    • 使用transformer,您可以以优雅、干净和更可控的方式加载相关模型,即使大小巨大,一个更大的好处是您可以转换结果,而不必担心如何循环 您可以简单地引用,以便对其进行简单的使用。然而,如果你不需要改变你的反应,那么你可以采取其他的选择
  • 虽然这可能不完整