2017-07-09 60 views
2

我目前正在編寫一個接口與大型數據庫並需要從中檢索大量數據的應用程序的API,然後將其吐出爲JSON。以更具內存效率的方式操作大陣列

我使用CodeIgniter(CI)作爲數據庫接口,但我不認爲它在這裏是相關的。我遇到了內存限制,我不幸沒有辦法增加限制,因爲共享主機服務不會這樣做。

我從數據庫中獲得約56k行,通過CI(零索引,非常標準)將其放入數組中。每行有7個字段。

一切都很好,直到我開始循環數組來修改數據。即使我只是修改原始數組,並且沒有分配新變量,我認爲在幾次循環迭代之後腳本會出現內存限制錯誤。

Allowed memory size of 134217728 bytes exhausted 

下面是我使用的代碼:

$query = $this->db->get('table'); 
if ($query->num_rows() > 0) { 
    $result = $query->result_array(); 
    foreach ($result as $k => $v) { 
     foreach($v as $key => $value) { 
      if ($key === 'column_name') { 
       $result[$k][$key] = json_decode($value); 
       continue; 
      } 
      if ($value == null) { 
       $result[$k][$key] = ''; 
      } else if (ctype_digit($value)) { 
       $result[$k][$key] = (int) $result[$k][$key]; 
      } 
     } 
    } 
    return $result; 
} 

只是一些解碼JSON和鑄造爲整數或空字符串,沒有什麼花哨。但是我會在改變$result數組的任何行上出現內存限制錯誤。即使我刪除(內存密集)json_decode我仍然會收到一個錯誤,只是簡單地將其轉換爲int

更重要的是,即使我刪除了整個foreach,但當我使用json_encode生成API響應時,稍後出現內存限制錯誤。我真的需要這麼多的數據一次輸出,不知道如何使這個更高的內存效率(也許有類似的緩衝區或什麼的?從未潛入此)。

編輯:對於任何感興趣的人,我設法通過對數據庫進行無緩衝的查詢來減少內存使用量。這樣,只有1份數據存儲在數組中。我也刪除了foreach,並專門處理每個字段。然而,主要問題可能是PHP stores arrays。下面是新的代碼:

$query = $this->db->get('table'); 
$result = []; 
while ($row = $query->unbuffered_row('array')) { 
    if ($row['column1'] == '[]') { 
     $row['column1'] = []; 
    } else { 
     $row['column1'] = json_decode($row['column1']); 
    } 
    $row['column2'] = (int) $row['column2']; 
    $row['column3'] = (int) $row['column3']; 
    $row['column4'] = is_null($row['column4']) ? '' : (int) $row['column4']; 
    $row['column5'] = is_null($row['column5']) ? '' : (int) $row['column5']; 

    $result[] = $row; 
} 

return $result; 
+0

什麼是PHP內存限制設置? – user2182349

+0

@ user2182349錯誤消息指出「允許的內存大小爲134217728個字節已耗盡」。將此問題添加到問題謝謝。 – beeb

+0

把它翻倍 - 你應該沒問題 – user2182349

回答

1

有這麼多的方法來解決這個問題,真正的問題會被你有什麼重點是什麼?

  • 它是否必須快?它可以慢嗎?
  • 那個低內存服務器是絕對唯一的可用資源嗎?

理想的解決方案顯然是升級你的服務器,假設你有任務消耗大量內存,這應該是誰運行這個項目的關注。

很明顯,現代的方式使用微服務來實現它,每個服務都處理一大塊數據。它們可以由您編寫,也可以使用AWS等雲服務。假設你確實限於目前的星座,並且你只是沒有其他選擇,只能使用有限的內存服務器來處理大數據,我會推薦使用本地文件I/O - 這不是最快的解決方案,但是如果您讀取數據塊並繼續將其寫入臨時文件,則可以節省內存問題,然後可以將該文件刷新到客戶端。

+0

感謝您的回答。我確實受到這臺服務器的限制,我希望他們能夠把它弄糟,服務器應該有更多的內存,但是直到明天當支持恢復時我纔會確定。我可以研究雲服務,這將是一個有趣的體驗。文件IO可能不是一個選項,因爲這必須有點快,但我會做一個測試,以確保。謝謝! – beeb

+0

如果他們想讓它變快,他們應該會給你更多的資源,至少可以控制php.ini :) 祝你好運! – Rony

+0

順便說一句 - 我不知道你的服務器客戶端是如何設置的,但是如果這個查詢是使用API​​調用完成的,你可以試着簡單地繼續輸出數據(echo)而不是將它存儲在數組中,這可能會起作用。 另一個解決方法是使用EventSource,它是一種可以保持客戶端和服務器之間連接的Web套接字(需要html5) – Rony