Existe uma maneira mais eficiente para executar consultas dentro de um loop?Problemas de memória

StackOverflow https://stackoverflow.com/questions/3856555

Pergunta

Eu tenho um site Joomla que eu escrevi um costume carrinho de compras componente.O usuário é, basicamente, códigos de compra, estamos armazenando em nosso banco de dados, estes são associados com impressão de um cartão de incentivo.Quando o usuário faz check-out, eu preciso pegar um bloco de códigos do banco de dados (no entanto, muitos tiver adquirido),, em seguida, percorra a lista de códigos e atualização de tabelas com informações em meu carrinho.O carrinho é armazenada como uma matriz de matrizes em uma variável de sessão, como este:

$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 ) 
) 

onde cada matriz interna é um item de linha no carrinho.É a quantidade que está causando o problema;quando elas são de baixo não há nenhum problema na execução de todos a atualização e inserção de consultas dentro do loop.No entanto, quando a quantidade de elementos estão em alta, eu começar a erros de alocação de memória.Isso é compreensível, pois é basicamente executando várias consultas centenas de vezes.O problema é, um usuário poderia, potencialmente, a ordem de um milhar de cartas ou mais de uma vez (esta é uma corporativa programa de incentivo), então eu preciso ser capaz de obter todos os registros inseridos e atualizados, independentemente de quão grande o é qtd.

Aqui está o código:

Primeiro, o loop:

//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);
}

O real, consultas que estão dentro do createPurchaseRecord e updateVoucherInfo funções do modelo:

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;

}

Alguém pode me ajudar?Tem que haver uma maneira de fazer isso mais eficiente;agora ele está jogando um erro de memória quando eu tento fazer mais do que 30 ou assim, de cada vez;dada a exigência para 1.000+, este é um grande negócio.Esse é o erro:

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

Linha 110 é esta linha do loop acima:

   $VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];
Foi útil?

Solução

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

Você está fazendo isso errado. Você concatena a lista para si mesma, resultando na variável que cresce exponencialmente.

Maneira correta:

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

ou

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

Atenciosamente, Alin

Outras dicas

Para tornar o código mais limpo e pouco mais eliminar chamadas desnecessárias.

Em vez de

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

Utilização

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

Aumentar a utilização da memória em php.ini

Se você estiver usando o PHP 5, solto &.

Em vez de loop através de matriz de matrizes.Carga $vouchers como conjunto de objetos, os objetos são passados por referência, em vez de pelo valor.

foreach($vouchers as $voucher) {

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

Com o. = Operador, você está fazendo uma concatenação de $VoucherIDList para si mesmo.

Com a declaração acima, você também adiciona $VoucherIDList para a lista novamente.

Como Alin disse acima, você está adicionando a variável para si mesma exponencialmente toda vez que o loop for executado.

Eu acho que é por isso que você está recebendo os problemas de erro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top