Есть ли более эффективный способ выполнения запросов внутри цикла?Проблемы с памятью - PullRequest
0 голосов
/ 04 октября 2010

У меня есть веб-сайт Joomla, для которого я написал специальный компонент корзины для покупок. Пользователь в основном покупает коды, которые мы храним в нашей базе данных - они связаны с печатной поощрительной картой. Когда пользователь выписывает счет, мне нужно взять кусок кода из базы данных (сколько бы он ни купил), затем просмотреть список кодов и обновить другие таблицы с информацией в моей корзине. Корзина хранится в виде массива массивов в переменной сеанса, например:

$cart = Array ( 
[0] => Array ( [TypeFlag] => S [qty] => 25 [denom] => 50  [totalPrice] =>  100 )
[1] => Array ( [TypeFlag] => V [qty] => 10 [denom] => 25  [totalPrice] => 25 ) 
[2] => Array ( [TypeFlag] => C [qty] => 100 [denom] => 25  [totalPrice] => 25 ) 
) 

где каждый внутренний массив - это одна позиция в корзине. Это кол-во вызывает проблему; когда они низкие, нет проблем с выполнением всех запросов вставки и обновления внутри цикла. Однако, когда количество элементов qty велико, я начинаю получать ошибки выделения памяти. Это понятно, поскольку он в основном выполняет несколько запросов сотни раз. Проблема заключается в том, что пользователь может потенциально заказывать тысячу или более карт одновременно (это корпоративная программа стимулирования), поэтому мне нужно иметь возможность вставлять и обновлять все записи независимо от того, насколько велико их количество.

Вот соответствующий код:

Сначала цикл:

//loop through vouchers to create purchase records, update voucher records, create certificates
$rightNow = date("YmdHis");
foreach($vouchers as $voucher) {
    $VoucherID = $voucher['VoucherID'];
    $VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];
    //create purchase record            
    $purchData = array("CcAuthCode"=>$ccAuthCode,"VoucherID"=>$VoucherID,"PurchAmt"=>$realFinalTotal, "ShipHandFee"=>number_format($shippingCharge,2),  "PurchDT"=>$rightNow,  "AcctID"=>$accountIDs['UserAcctID'], "ShipAddrID"=>$accountIDs['MailingAcctID']);
    $purchID = $model->createPurchaseRecord($purchData);    

    //update voucher
    $model->updateVoucherInfo($VoucherID,$accountIDs['BillingAcctID'], $denom, $purchID,$message);
}

Фактические запросы находятся внутри функций createPurchaseRecord и updateVoucherInfo в модели:

function createPurchaseRecord($data){    
    $db =& JFactory::getDBO();
    $insFields = "";
    $valFields = "";

    foreach ($data as $f => $v){
        $insFields .= "," . $f;
        $valFields .= "," . $db->quote($v);
    }

    $insFields = substr($insFields,1);
    $valFields = substr($valFields,1);

    $query = "insert into arrc_PurchaseActivity ({$insFields}) values ({$valFields})";
    $db->setQuery($query);
    if (!$db->query()) error_log($db->stderr());

    return $db->insertid();
}

function updateVoucherInfo($voucherID,$billingAcctId, $balanceInit, $purchID, $certMessage) {
    //set ActivatedDT, BalanceInit
    $rightNow = date("YmdHis");
    $db =& JFactory::getDBO();
    $query = "UPDATE arrc_Voucher 
        set ActivatedDT=".$db->quote($rightNow).", BalanceInit=".$db->quote($balanceInit) . ", BalanceCurrent=".$db->quote($balanceInit).
    ", AcctID=".$db->quote($billingAcctId).", PurchActvtyID=".$db->quote($purchID) . ", certMessage=".$db->quote($certMessage)
    . " WHERE VoucherID=".$db->quote($voucherID);

    $db->setQuery($query);
    if (!$db->query()) error_log($db->stderr()); 
    $certificateNumber = $voucherID;
    return $certificateNumber;

}

Кто-нибудь может мне помочь? Должен быть способ сделать это более эффективным; сейчас он выдает ошибку памяти, когда я пытаюсь сделать больше, чем 30 или около того одновременно; учитывая требование 1000+, это большое дело. Это ошибка:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71303153 bytes) in /var/www/html/mysite.com/components/com_arrcard/controllers/checkout.php on line 110

Строка 110 - это строка из вышеприведенного цикла:

   $VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];

Ответы [ 3 ]

3 голосов
/ 04 октября 2010
$VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];

Вы делаете это неправильно.Вы соединяете список с самим собой, приводя к экспоненциальному росту переменной.

Правильный путь:

$VoucherIDList .= "," . $voucher['VoucherNbr'];

или

$VoucherIDList = $VoucherIDList ."," . $voucher['VoucherNbr'];

С уважением, Алинь

1 голос
/ 04 октября 2010

Чтобы сделать ваш код немного чище и устранить ненужные вызовы.

Вместо

foreach ($data as $f => $v){
    $insFields .= "," . $f;
    $valFields .= "," . $db->quote($v);
}

Использование

$valFields = implode(',', $data);
$insFields = implode(',', array_keys($data));

Увеличение использования памяти в php.ini

Если вы используете PHP 5, потеряйте &.

Вместо циклического перебора массива массивов.Загружайте $vouchers как массив объектов, объекты передаются по ссылке, а не по значению.

foreach($vouchers as $voucher) {
0 голосов
/ 04 октября 2010

$VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];

С оператором. = Вы делаете конкатенацию $VoucherIDList для себя.

Используя приведенное выше утверждение, вы также добавляете $VoucherIDList в список снова.

Как сказал Алин выше, вы добавляете переменную к себе экспоненциально при каждом запуске цикла.

Я думаю, именно поэтому у вас возникают проблемы с ошибкой.

...