Повышение производительности при обновлении большой таблицы, Laravel - PullRequest
2 голосов
/ 18 июня 2020

У меня есть функция, которая должна запускаться раз в неделю (задание cron), и теперь я пытаюсь провести стресс-тест.

В моем запросе я получаю:

Максимум время выполнения 60 секунд превышено.

protected function updateAnswerHistory(){
    $answer_statistics = AnswerStatistic::select('question_id','paragraph_id','lkp_answer_id')->get(); //about 500row

    $history = AnswerHistory::select('id', 'question_id','paragraph_id','lkp_answer_id','correct_answer_score')->get(); //about 40k rows

    foreach ($history as $row) {

        if($row->question_id){
            $lkp_answer_id = $answer_statistics->where('question_id', $row->question_id)->pluck('lkp_answer_id')->first();
            if($row->lkp_answer_id === $lkp_answer_id){
                $row->update(['correct_answer_score' => 7]);
            }else{
                $row->update(['correct_answer_score' => 4]);
            }
        }

        if($row->paragraph_id){
            $lkp_answer_id = $answer_statistics->where('paragraph_id', $row->paragraph_id)->pluck('lkp_answer_id')->first();
            if($row->lkp_answer_id === $lkp_answer_id){
                $row->update(['correct_answer_score' => 7]);
            }else{
                $row->update(['correct_answer_score' => 4]);
            }
        }
    }
}

Плохо то, что query from foreach требует времени, но я не уверен, как это улучшить.

Ответы [ 2 ]

2 голосов
/ 18 июня 2020

Я не уверен, что правильно понимаю вашу структуру таблиц db,

но получение данных из db и их обновление дорого обходятся

вы должны выполнить процесс обновления в db любым путь ...

идея этого кода состоит в том, чтобы объединить две таблицы на основе столбца question_id, а затем выполнить обновление 'где', у меня не было возможности проверить это ...

AnswerHistory::join('answer_statistics','answer_statistics.question_id','answer_histories.question_id')-> where('answer_histories.question_id','!=',null)->
    where('answer_histories.lkp_answer_id','=',DB::raw('answer_statistics.lkp_answer_id'))
        ->update(['correct_answer_score' => 3]);

AnswerHistory::join('answer_statistics','answer_statistics.question_id','answer_histories.question_id')-> where('answer_histories.question_id','!=',null)->
    where('answer_histories.lkp_answer_id','!=',DB::raw('answer_statistics.lkp_answer_id'))
        ->update(['correct_answer_score' => 0]);

дайте знать, если поможет

0 голосов
/ 18 июня 2020

При извлечении большого набора данных использование фасада DB выполняется быстрее, чем использование Eloquent Model, так как оно сокращает время преобразования записи db в красноречивую модель

А также, поскольку массовое обновление выполняется быстрее, чем обновление одной строки, вы может сделать это как

$questionList = DB::table('answer_history')
 ->join('answer_statistic')
 ->on('answer_history.question_id', 'answer_statistic.question_id')
 ->on('answer_history.lkp_answer_id', 'answer_statistic.lkp_answer_id')
 ->whereNull('answer_statistic.deleted_at')
 ->pluck('answer_history.id')
 ->toArray();


$paraList = DB::table('answer_history')
 ->join('answer_statistic')
 ->on('answer_history.paragraph_id', 'answer_statistic.paragraph_id')
 ->on('answer_history.lkp_answer_id', 'answer_statistic.lkp_answer_id')
 ->whereNull('answer_statistic.deleted_at')
 ->pluck('answer_history.id')
 ->toArray();

$ids7 = array_merge($questionList,$paraList); 

AnswerHistory::wherein('id', $ids7) >update(['correct_answer_score' => 7]);
AnswerHistory::whereNotin('id',$ids7 )->update(['correct_answer_score' => 4]);

Отредактировано: innerjoin -> join

...