mysql语句 - > fetch()在循环时失败

时间:2017-10-18 14:16:03

标签: php mysql mysqli pdo

我有一个使用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;

1 个答案:

答案 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的类来执行此操作,以封装查询并在获取行时一次返回一行。