2017-10-18 96 views
0

我有一個使用PHP(5.6.28)和Mysql編寫的休息API。我試圖實現的目標是從數據庫中提取135k條記錄。mysql statement-> fetch()循環失敗

查詢執行得很好,我可以得到好的行數。但是,在循環遍歷結果並將它們添加到數組中時,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

在處理了一定數量的行後,使用迭代器檢查內存使用量,結果發現腳本使用像285mb的ram,腳本因此失敗。我增加了內存限制,並解決了問題。有關如何減少內存消耗的任何想法? –

回答

0

正如你提到的,你超過了內存限制,這是128MB默認情況下在PHP 5.6。

您正在提取135k行。請注意,在開始提取之前,store_result()整個結果集傳輸到PHP的內存中。在這種模式下,fetch()實際上只是迭代已經在內存中的結果集。因此,當你填充你的數組時,你基本上將結果集存儲在你的存儲器中兩次。

另一種方法是調用use_result(),它不預取結果集。每次調用fetch()都會從MySQL服務器獲取下一行。處理大型結果集時,這是減少內存使用的常用方法。

然後你在一個數組中存儲135k行。每行有七個字段。我猜想其中一些是數字。您可以嘗試將這些轉換爲二進制表示,理論上說本地整數佔用的空間比數字的字符串表示要少。

$delivery_item['volume']   = (int) $client_delivery_item_volume; 

我不知道你的數據,但這可能是唯一的情況下,你可以強制轉換爲int。 PHP也有一個浮點類型,但是我不推薦使用float作爲貨幣值,因爲舍入問題。

我唯一的其他建議是避免將整個數組存儲在內存中,但要構造您的應用程序,以便您可以一次處理一行。我通過編寫這個函數作爲一個實現Iterator的類來執行此操作,以封裝查詢並在獲取行時一次返回一行。