Оптимизируйте запрос к базе данных, чтобы избежать проблем с памятью - PullRequest
0 голосов
/ 12 сентября 2018

У меня огромная таблица Users (может быть, около 4M строк), и я хочу запускать ежемесячное задание для проверки даты последнего входа в систему, и если они не вошли в систему, обновите пользователя и обновите столбец isPassive со значением true.

$users = \DB::table('users')
                   ->whereNull('isPassive')->get();
foreach($users as $user)
{
   if(!$user->wasActive())
   {
      $this_user = (new User)::where('id', $user->id)->first();
      $this_user->isPassive = true;
      $this_user->save();
   }
}

Я научился запускать задания с помощью Laravel, но это вызывает у меня проблемы с памятью.Ну, я могу увеличить память сервера, но из того, что я прочитал здесь, увеличение памяти не всегда является лучшим решением.

Я пробовал результаты чанка , но когда я использую where(), этопросто виснет.Если я использую его без условий и условия, то все работает хорошо.

Мне интересно, как опытный разработчик сломает эту работу, чтобы использовать меньше памяти?

Помечен как Laravel, но это вопрослюбой новый программист может столкнуться при обучении лучше управлять памятью.

Спасибо за любой совет

1 Ответ

0 голосов
/ 12 сентября 2018

Есть несколько проблем с вашим кодом. Во-первых:

$this_user = (new User)::where(...)->first();
...

Эта строка запускает новый запрос на каждой итерации цикла foreach, поэтому вы, по сути, выполняете 4 миллиона дополнительных ненужных запросов. Этот запрос является избыточным, так как у вас уже есть $user, и $this_user будет то же самое. Измените свой код следующим образом:

$users = User::whereNull('isPassive')->get();
foreach($users AS $user){
  if(!$user->wasActive()){
    $user->isPassive = true;
    $user->save();
  }
}

С этим вы сократили свои запросы пополам.

Кроме того, я не уверен, что делает метод wasActive(), но если вы можете переместить эту логику в исходный запрос, вы, вероятно, можете удалить цикл, выполнив один оператор update:

DB::table("users")
->whereNull("isPassive")
->where(...) // Apply logic from User wasActive() check
->update(["isPassive" => true]);

Надеюсь, это поможет.

...