我有一个工作API(php-laravel),可以根据需要返回正确的数据。我自己是一个java家伙,我无法完全理解出了什么问题。代码是由自由职业者编写的,我正在慢慢学习laravel。
问题是如果调用此特定API(甚至一次),服务器上的CPU使用率达到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响应时间会快得多,而且它也只能将CPU加载到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 requests
Server 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 在上面的代码中,有一个外部呼叫&#34;用户&#34;模特班;一个名为&#34; getPromoSummaryIdsWhereUserHasCards&#34;特别。这里有2个foreach循环。如果我打印并检查一些日志这些for循环正在执行很多次!
/**
* @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;
}
}
答案 0 :(得分:0)
嗯,基本上这是在做什么就是查询某事。类似于以下内容:
-- 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();
但请注意,如果只是大量的数据,这只需要时间。考虑在这种情况下添加聪明的索引!