¿Hay una manera más eficiente para ejecutar consultas dentro de un bucle? problemas de memoria

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

Pregunta

Tengo un sitio web Joomla que he escrito un componente carrito de la compra personalizado para. El usuario está comprando básicamente códigos que estamos almacenando en nuestra base de datos - estos están asociados con una tarjeta de reclamo impreso. Cuando los controles de usuario, necesito para tomar un trozo de códigos de la base de datos (no obstante las muchas que han comprado), a continuación, recorrer la lista de códigos y actualizar otras tablas con información en mi carrito. El carro se almacena como una matriz de matrices en una variable de sesión, así:

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

donde cada matriz interna es un elemento de línea en el carrito. Es el qty que está causando el problema; Cuando están bajo no hay problema al ejecutar todas las consultas de inserción y actualización dentro del bucle. Sin embargo, cuando los elementos Cant son altos, que comienza a recibir los errores de asignación de memoria. Esto es comprensible, ya que es básicamente ejecutar varias consultas cientos de veces. La cuestión es, un usuario podría potencialmente orden de mil cartas o más a la vez (este es un programa de incentivos de empresa), así que tengo que ser capaz de obtener todos los registros insertados y actualizados, sin importar cuán grande es el qty es.

Este es el código correspondiente:

En primer lugar, el bucle:

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

Las consultas reales están dentro de las funciones createPurchaseRecord y updateVoucherInfo en el 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;

}

Alguien me puede ayudar? Tiene que haber una manera de hacer esto más eficiente; en este momento se está lanzando un error de memoria cuando trato de hacer más de 30 o menos a la vez; dada la necesidad de más de 1,000, esto es un gran problema. Este es el error:

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

Line 110 es esta línea desde el bucle de arriba:

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

Solución

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

Se están haciendo esto mal. Concatena la lista a sí mismo lo que resulta en la variable de crecimiento exponencial.

Forma correcta:

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

o

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

Saludos, Alin

Otros consejos

Para hacer que su código de poco más limpio y eliminar las llamadas innecesarias.

En lugar de

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

Uso

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

Uso de aumentar la memoria en php.ini

Si está usando PHP 5, & suelto.

En lugar de bucle a través de matriz de matrices. Cargar $vouchers como matriz de objetos, los objetos se pasa por referencia en lugar de por valor.

foreach($vouchers as $voucher) {

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

Con el. = Operador que está haciendo una concatenación de $VoucherIDList a sí mismo.

Con la declaración anterior, a continuación, también se añade a la lista $VoucherIDList de nuevo.

Al igual que Alin dijo anteriormente, que está añadiendo la variable a sí mismo de forma exponencial cada vez que se ejecuta el bucle.

Yo diría que esta es la razón de que está recibiendo los problemas de error.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top