我有一个使用PHP(5.6.28)和Mysql编写的rest API。我想要实现的是从数据库中提取135k记录。
查询执行正常,我可以得到行数。但是在循环结果并将它们添加到数组中时,php会在没有错误的情况下停止执行。
我检查了php错误(没有错误记录btw),增加了最大执行时间(300secs),内存(256M)数量等。从mysql工作台执行时,sql查询工作(完成15secs)。 Php脚本像16secs一样死掉。
我们如何调试这样的东西?或者你的解决方案是什么?您可以在下面找到代码。
set_time_limit(300); //allow php to run until query completes
ini_set('max_execution_time', 300);
$sql = "SELECT client_delivery_item_dest_address1, client_delivery_item_dest_address3, client_delivery_item_volume,
client_delivery_item_transport_charge, client_delivery_item_waybill_number,client_deliveries.client_delivery_insert_date,
client_delivery_item_barcode
FROM client_deliveries
INNER JOIN client_delivery_items ON client_deliveries.client_delivery_id = client_delivery_items.client_delivery_id
WHERE " . $date_where . " " . $branch_where . "
AND client_deliveries.source_branch_id=3 AND client_deliveries.is_transfer=0
ORDER BY client_delivery_insert_date ASC";
$statement = $this->prepare($sql);
$statement->bind_result($client_delivery_item_dest_address1, $client_delivery_item_dest_address3, $client_delivery_item_volume,
$client_delivery_item_transport_charge, $client_delivery_item_waybill_number, $client_delivery_insert_date, $client_delivery_item_barcode);
//return array('sql' => $sql); used this to get the actual that is running
if (!$statement->execute()) {
return array('error' => "Execute failed: (" . $stmt->errno . ") " . $stmt->error); //execution doesnt fail apparently
}
$statement->store_result();
//return array('rowcount' => $statement->num_rows); returns 134411 it is the correct number of rows
while ($statement->fetch()) {
$delivery_item = array();
$delivery_item['store_code'] = $client_delivery_item_dest_address1;
$delivery_item['store_city'] = $client_delivery_item_dest_address3;
$delivery_item['volume'] = $client_delivery_item_volume;
$delivery_item['price'] = $client_delivery_item_transport_charge;
$delivery_item['waybill_number'] = $client_delivery_item_waybill_number;
$delivery_item['delivery_date'] = $client_delivery_insert_date;
$delivery_item['barcode'] = $client_delivery_item_barcode;
array_push($delivery_items, $delivery_item);
//return $delivery_items; returns first row correctly
}
//the execution dies before here
$statement->close();
return $delivery_items;
答案 0 :(得分:0)
如您所述,您超出了内存限制,默认情况下在PHP 5.6中为128 MB。
您正在获取135k行。请注意,store_result()
会在开始提取之前将整个结果集传输到PHP的内存中。在这种模式下,fetch()
实际上只是迭代已经在内存中的结果集。因此,当您填充$delivery_items
数组时,您实际上将结果集存储在内存中两次。
另一种方法是调用use_result(),它不预取结果集。每次调用fetch()
都会从MySQL服务器获取下一行。这是在处理大型结果集时减少内存使用的常用方法。
然后你在数组中存储135k行。每行有七个字段。我猜其中一些是数字的。您可以尝试将这些转换为二进制表示,理论上原生整数比数字的字符串表示占用更少的空间。
$delivery_item['volume'] = (int) $client_delivery_item_volume;
我不知道您的数据,但这可能是您可以转换为int的唯一情况。 PHP也有浮点类型,但由于四舍五入问题,我不建议使用浮点数作为货币值。
我唯一的另一个建议是避免将整个数组存储在内存中,但要构建应用程序,以便每次处理一行。我通过将此函数编写为实现Iterator的类来执行此操作,以封装查询并在获取行时一次返回一行。