需要帮助优化laravel - php代码

时间:2015-03-16 08:13:28

标签: php mysql laravel backend

我有一个工作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;
    }

}

1 个答案:

答案 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();

但请注意,如果只是大量的数据,这只需要时间。考虑在这种情况下添加聪明的索引!