简体   繁体   中英

Fast compute average monthly sales for the past 6, 3, 1 months per product

I'm using PHP/MySQL

I have about 2,000 products. I have to compute the average monthly sales for the past 6, 3, 1 month(s) of each product and show it in the page at once...

Currently I have the following code (loop for each product):

$past_month_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
                                                                $item_code, $past_month[0],
                                                                $past_month[1] );

$past_two_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
                                                                    $item_code, $past_two_months[0],
                                                                    $past_two_months[1] );

$past_three_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
                                                                    $item_code, $past_three_months[0],
                                                                    $past_three_months[1] );

$past_four_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
                                                                    $item_code, $past_four_months[0],
                                                                    $past_four_months[1] );

$past_five_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
                                                                    $item_code, $past_five_months[0],
                                                                    $past_five_months[1] );

$past_six_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
                                                                    $item_code, $past_six_months[0],
                                                                    $past_six_months[1] );

//for past 3 months
if( $past_month_sales == 0
    || $past_two_months_sales == 0
    || $past_three_months_sales == 0){

    $past_three_sales_ave = "n/a";

}else{

    $past_three_sales_ave = round( ( $past_month_sales 
                        + $past_two_months_sales
                        + $past_three_months_sales )
                        / 3 );
}

//for past 6 months
if( $past_month_sales == 0
    || $past_two_months_sales == 0
    || $past_three_months_sales == 0
    || $past_four_months_sales == 0
    || $past_five_months_sales == 0
    || $past_six_months_sales == 0){

    $past_six_sales_ave = "n/a";

}else{
    $past_six_sales_ave = round( ( $past_month_sales
                        + $past_two_months_sales
                        + $past_three_months_sales
                        + $past_four_months_sales
                        + $past_five_months_sales
                        + $past_six_months_sales )
                        / 6 );
}

But the code above is very slow, even 100 products take ages to load...

My getSalesForMonthYear function look like this:

function getSalesForMonthYear( $account_code, $item_code, $month, $year ){
    $sql = "select 
                SalesPerProduct.sales_value
            from 
                sales_per_products as SalesPerProduct
            where
                account_code = '{$account_code}' and
                item_code = '{$item_code}' and
                month = '{$month}' and
                year = '{$year}'";

    $val = $this->query($sql);

    if( empty( $val[0]['SalesPerProduct']['sales_value'] ) ){
        $val = 0;
    }else{
        $val = $val[0]['SalesPerProduct']['sales_value'];
    }
    return $val;
}

Any idea how this can be fast? TIA!!!

您不需要每次单击都更新数据,因此建立一个缓存表来保存数据并在每个时间段更新

You should look in to SQL commands like AVG

http://www.w3schools.com/sql/sql_func_avg.asp

Its always better to do the calculation on the database side. No code you write will go faster than doing it before extracting it.

See that you have index your database good so it know what to do and when!

Thats the first you could do!

I think it will solve alot for you at this point.

If you then want to take it even one step futher you could check in to this.

http://www.sqlteam.com/article/intro-to-user-defined-functions-updated http://www.w3schools.com/sql/sql_view.asp

You could create a function and view that extract all avg calls in one sql query. No need for several connections. Every connection will have some overhead starting up and so on that you could by pass again by doing everything on the database side!

maybe use an general function and don't check for each month. and try to use indexes for months and sales_value

/*
   $account_code - account
   $item_code - item
   $start_month - starting month - NOTE: this is integer: 1,2,....,10,11,12
   $months - number of months to query
   $year - the year
   and SUM to auto calculate the sales_value
*/
function getSalesForMonths( $account_code, $item_code, $start_month, $months, $year ){
    $addQuery = '';
    $finalQuery = '';

    for($i = 1; $i<=$months; $i++){
         $addQuery .= 'month='.($start_month+$i);
         if($i<$months){ $addQuery .= ' OR '; }
    }

    if($months > 1){
        $finalQuery = '('.$addQuery.')';
    } else {
        $finalQuery = $addQuery;
    }

    $sql = "select 
            SUM(SalesPerProduct.sales_value)
        from 
            sales_per_products as SalesPerProduct
        where
            account_code = '{$account_code}' and
            item_code = '{$item_code}' and
            ".$finalQuery." and
            year = '{$year}'";

    $val = $this->query($sql);

    if( empty( $val[0]['SalesPerProduct']['sales_value'] ) ){
        $val = 0;
    }else{
        $val = $val[0]['SalesPerProduct']['sales_value'];
    }
    return $val;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM