Многократное обновление Laravel - PullRequest
0 голосов
/ 18 ноября 2018

У меня есть приложение laravel 5.6, которое перечисляет элементы на странице и одновременно собирает просмотры. На создание страницы в среднем ушло 8 секунд.

Элемент таблицы

CREATE TABLE IF NOT EXISTS items (
id INT AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
views INT NOT NULL,
PRIMARY KEY (id)
)  ENGINE=INNODB;

Таблица items_daily_views

CREATE TABLE IF NOT EXISTS items_daily_views (
id INT AUTO_INCREMENT,
item_id INT NOT NULL,
date DATE NOT NULL,
views INT NOT NULL,
PRIMARY KEY (id)
)  ENGINE=INNODB;

Модель товара

class Item extends Model{
  protected $table='items';
}

Модель ItemDailyViews

class ItemDailyViews extends Model{
  protected $table='items_daily_views';
}

HomeController.php

$itemList = Item::orderBy('id','desc')->take(100)->get();
foreach($itemList as $item){
   //increment to items
   $each=Item::find($item->id);
   $each->increment('views');

   //increment to items_daily_views
   $each=ItemDailyViews::updateOrCreate(
       ['item_id'=>$item->id,
        'date'=>Carbon::now()->format('Y-m-d')]
   );
   $each->increment('views');
}

return view('home',['itemList',$itemList]);

Эта страница содержит около 200 запросов на обновление, на создание которых ушло 8 секунд. Прежняя версия этого приложения использует чистый PHP без laravel и использует для генерации около 10 миллисекунд (также значительно меньше оперативной памяти). Я должен сделать что-то не так. Пожалуйста помоги. Спасибо!

Ответы [ 3 ]

0 голосов
/ 18 ноября 2018

Попробуйте это:

$itemList = Item::orderBy('id','desc')->take(100)->get();
foreach($itemList as &$item){ // pass by reference since you are modifying within foreach
   //increment to items
   $item->increment('views');

   //increment to items_daily_views
   $dailyViews = ItemDailyViews::firstOrCreate(
       ['item_id'=>$item->id,
        'date'=>Carbon::now()->format('Y-m-d')]
   );
   $dailyViews->increment('views');
}

return view('home',['itemList',$itemList]);
0 голосов
/ 18 ноября 2018
$itemList = Item::orderBy('id','desc')->take(100)->get();
$itemDailyViews=[];
foreach($itemList as $item){
   //increment to items
   $item->itemDailyViews->date = Carbon::now()->format('Y-m-d');
   $item->itemDailyViews->increment('views');
   array_push($itemDailyViews,$item->itemDailyViews);

}
$itemList->itemDailyViews()->saveMany($itemDailyViews);
return view('home',['itemList',$itemList]);

Это сработает, если вы дали правильные красноречивые отношения.

0 голосов
/ 18 ноября 2018

IDEA

Может быть, вместо того, чтобы делать это в laravel-eloquent, попробуйте отправить необработанный SQL-запрос, используя DB::statement("UPDATE ..."), который обновляет сразу все просматриваемые строки внутри БД (ниже sql я пишу из головы - протестируйте его (может содержать ошибки)):

UPDATE items
    SET views = views + 1
    ORDER BY id DESC
    LIMIT 100;

Вы можете использовать WHERE clausule, чтобы выбрать правильные строки, которые вы хотите обновить. И используйте аналогичный механизм для таблицы items_daily_views (это немного сложнее, потому что сначала вы должны проверить, что существует правильная строка данного дня ( создать, если не ), а затем обновить его счетчик просмотров). В этом методе вы сможете избежать отправки более ~ 200 sql отдельных запросов в БД с php (и отправлять только несколько запросов).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...