mysql — нужна помощь в оптимизации laravel — php code

У меня есть рабочий API (php-laravel), который возвращает правильные данные по мере необходимости. Будучи парнем из Java, я не могу полностью понять, что происходит не так. Код был написан фрилансером, и я медленно изучаю Laravel.

Проблема в том, что если этот конкретный API вызывается (хотя бы один раз), загрузка ЦП на сервере достигает 100%, что не должно иметь место.

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

$has_promo_for_users_cards = in_array($promo_summary_id, \User::getPromoSummaryIdsWhereUserHasCards($user_id));
$promo_summary['has_promo_for_users_cards'] = $has_promo_for_users_cards;
// see if the promo is applicable to users cards
if ($has_promo_for_users_cards)
{
$applicable_cards = [];
$filter_cards = $inputs['filter_cards'];

$user_card_ids = $filter_cards == 'my_cards' ? \User::getUsersCardIds($user_id) : explode(',', $inputs['specific_cards']);
foreach ($cards as $card)
{
if (in_array($card['id'], $user_card_ids))
{
array_push($applicable_cards, $card);
}
}

} else
{
// if not applicable then return all the cards
$applicable_cards = $cards;
}
$promo_summary['applicable_cards'] = $applicable_cards;
return $promo_summary;

И возвращает все данные promo_summary.

После долгих экспериментов, если я закомментирую приведенный выше фрагмент, время отклика API будет намного быстрее, а также загрузка ЦП только до 10%. Поэтому я думаю, что проблема заключается в этом фрагменте. Любые предложения о том, как это можно оптимизировать? Есть ли что-то, что сделано неправильно?

РЕДАКТИРОВАТЬ 1

Вот результаты тестов сервера:

ab -n 1000 -c 5 http://111.111.111.111/index.html
This is ApacheBench, Version 2.3 <$Revision: 1554214 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 111.111.111.111 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requestsServer Software:        Apache/2.4.7
Server Hostname:        111.111.111.111
Server Port:            80

Document Path:          /index.html
Document Length:        59598 bytes

Concurrency Level:      5
Time taken for tests:   51.674 seconds
Complete requests:      1000
Failed requests:        113
(Connect: 0, Receive: 0, Length: 113, Exceptions: 0)
Non-2xx responses:      1000
Total transferred:      60176968 bytes
HTML transferred:       59597874 bytes
Requests per second:    19.35 [#/sec] (mean)
Time per request:       258.372 [ms] (mean)
Time per request:       51.674 [ms] (mean, across all concurrent requests)
Transfer rate:          1137.25 [Kbytes/sec] received

Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        4    6   1.9      5      56
Processing:   102  252 129.6    175     762
Waiting:       84  231 128.1    154     609
Total:        107  258 129.7    181     767

Percentage of the requests served within a certain time (ms)
50%    181
66%    288
75%    321
80%    336
90%    471
95%    579
98%    616
99%    619
100%    767 (longest request)

РЕДАКТИРОВАТЬ 2
В приведенном выше коде есть внешний вызов к классу модели «Пользователь»; Специально называется функция «getPromoSummaryIdsWhereUserHasCards». Здесь есть 2 цикла foreach друг в друге. Если я печатаю и проверяю некоторые журналы, эти циклы выполняются довольно много раз!

 /**
* @param $user_id
* @return array promo_summary_ids_where_user_has_cards
*/
public static function getPromoSummaryIdsWhereUserHasCards($user_id)
{
//logs
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");

//THE BELOW LINE IS TAKING TIME TO EXECUTE
$user = \User::with('cards.promos.promo_summary.establishment')->findOrFail($user_id);

$user_cards = $user->cards;
$promo_summary_ids_where_user_has_cards = [];
foreach ($user_cards as $user_card)
{
error_log( "Foreach user_cards--!");
$promos = $user_card->promos;
foreach ($promos as $promo)
{
error_log( "Foreach promos--!");

$promo_summary = $promo->promo_summary;
array_push($promo_summary_ids_where_user_has_cards, $promo_summary->id);
}
}

return array_unique($promo_summary_ids_where_user_has_cards);
}

РЕДАКТИРОВАТЬ 3
Модель PromoSummary

<?php

class PromoSummary extends \Eloquent {

protected $guarded = [];

public function promos()
{
return $this->hasMany('Promo', 'promo_summary_id');
}public function establishment()
{
return $this->belongsTo('Establishment', 'establishment_id');
}

public function searchTags()
{
return $this->hasMany('SearchTag', 'promo_summary_id');
}

/**
* @param $value
* @return mixed
* This is where the Establishment Image url is overriding the image_url in the promo summary.
* If need to change back to normal behaviour change here
*/
public function getImageUrlAttribute($value)
{
return $this->establishment->image_url;
}

}

1

Решение

Ну, в основном, это то, что он делает, это запрашивает что-то. похож на следующее:

-- note that i dont know you schema so the identifiers of the tables and columns
-- can be inceorrect, but you should get the idea

SELECT DISTINCT(promio_summaries.id)
FROM users, promos, promo_summaries
WHERE user.id = $user_id -- your method parameter
AND promos.user_id = $user_id
AND promo_summaries.promo_id = promos.id;

Так что, если это все, попробуйте выполнить это в вашей базе данных, посмотрите, не быстрее ли это, а затем вставьте это как запрос к БД вместо циклов.

// never done that, probably fails if copy pasted,
// but it should get you going.
return
DB::table('users')
->join('promos', 'promos.user_id', '=', 'users.id')
->join('promo_summaries', 'promo_summaries.promo_id', '=', 'promos.id')
->where('users.id', '=', $user_id)
->select(`promo_summaries.id`)
->distinct()->get();

Но имейте в виду, что если это просто огромное количество данных, это просто займет время. Рассмотрите возможность добавления умных индексов и в этом случае!

0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector