有没有更有效的方法在循环内运行查询?内存问题
我有一个 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 )
)
其中每个内部数组都是购物车中的一个行项目。导致问题的是数量;当它们较低时,在循环内运行所有插入和更新查询没有问题。但是,当元素数量很高时,我开始出现内存分配错误。这是可以理解的,因为它基本上运行了数百次查询。问题是,用户可能会一次订购一千张或更多卡(这是一个公司激励计划),因此我需要能够插入和更新所有记录,无论数量有多大。
这是相关代码:
首先,循环:
//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 个左右时,它会抛出内存错误;考虑到 1,000+ 的要求,这是一个大问题。这是错误:
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'];
I have a Joomla website that I've written a custom shopping cart component for. The user is basically purchasing codes we're storing in our database - these are associated with a printed incentive card. When the user checks out, I need to grab a chunk of codes from the database (however many they've purchased), then loop through the list of codes and update other tables with information in my cart. The cart is stored as an array of arrays in a session variable, like this:
$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 )
)
where each internal array is one line item in the cart. It's the qty that's causing the problem; when they're low there's no problem running all the insert and update queries inside the loop. However, when the qty elements are high, I start getting memory allocation errors. This is understandable, as it's basically running several queries hundreds of times. The issue is, a user could potentially order a thousand cards or more at a time (this is a corporate incentive program), so I need to be able to get all records inserted and updated, regardless of how big the qty is.
Here's the relevant code:
First, the 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);
}
The actual queries are inside the createPurchaseRecord and updateVoucherInfo functions in the model:
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;
}
Can anyone help me out? There has to be a way to make this more efficient; right now it's throwing a memory error when I try to do any more than 30 or so at a time; given the requirement for 1,000+, this is a big deal. This is the 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 is this line from the loop above:
$VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你这样做是错误的。您将列表与其自身连接起来,导致变量呈指数增长。
正确的方法:
或
问候,
阿林
You are doing this wrong. You concatenate the list to itself resulting in the variable growing exponentially.
Correct way:
or
Regards,
Alin
让您的代码更干净并消除不必要的调用。
而不是
使用
增加 php.ini 中的内存使用量
如果您使用的是 PHP 5,请放松
&
。而不是遍历数组的数组。将
$vouchers
加载为对象数组,对象通过引用而不是值传递。To make your code little cleaner and eliminate unnecessary calls.
Instead of
Use
Increase memory usage in php.ini
If you are using PHP 5, loose
&
.Instead of looping through array of arrays. Load
$vouchers
as array of objects, objects are passed by reference instead of by value.$VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];
使用 .= 运算符,您可以将
$VoucherIDList
与其自身连接起来。通过上述语句,您还可以再次将
$VoucherIDList
添加到列表中。就像 Alin 上面所说的那样,每次循环运行时,您都会以指数方式将变量添加到自身。
我猜这就是您遇到错误问题的原因。
$VoucherIDList .= $VoucherIDList ."," . $voucher['VoucherNbr'];
With the .= operator you are doing a concatenation of
$VoucherIDList
to itself.With the statement above, you then also add
$VoucherIDList
to the list again.Like Alin said above, you are adding the variable to itself exponentially every time the loop runs.
I would guess this is why you are getting the error problems.