2009-10-08 23 views
4

因此,我有一個PHP頁面,允許用戶下載CSV文件,查看可能是一大堆記錄的內容。問題是MySQL查詢返回的結果越多,它使用的內存就越多。這並不令人感到意外,但確實存在問題。在處理MySQL查詢結果時如何限制PHP內存使用量?

我嘗試使用mysql_unbuffered_query(),但並沒有任何區別,所以我需要釋放所用什麼,我認爲是以前處理的行存儲一些其他的方式。有沒有一個標準的方法來做到這一點?

這裏有一個評論日誌說明了什麼我談論:

// Method first called 
2009-10-07 17:44:33 -04:00 --- info: used 3555064 bytes of memory 

// Right before the query is executed 
2009-10-07 17:44:33 -04:00 --- info: used 3556224 bytes of memory 

// Immediately after query execution 
2009-10-07 17:44:34 -04:00 --- info: used 3557336 bytes of memory 

// Now we're processing the result set 
2009-10-07 17:44:34 -04:00 --- info: Downloaded 1000 rows and used 3695664 bytes of memory 
2009-10-07 17:44:35 -04:00 --- info: Downloaded 2000 rows and used 3870696 bytes of memory 
2009-10-07 17:44:36 -04:00 --- info: Downloaded 3000 rows and used 4055784 bytes of memory 
2009-10-07 17:44:37 -04:00 --- info: Downloaded 4000 rows and used 4251232 bytes of memory 
2009-10-07 17:44:38 -04:00 --- info: Downloaded 5000 rows and used 4436544 bytes of memory 
2009-10-07 17:44:39 -04:00 --- info: Downloaded 6000 rows and used 4621776 bytes of memory 
2009-10-07 17:44:39 -04:00 --- info: Downloaded 7000 rows and used 4817192 bytes of memory 
2009-10-07 17:44:40 -04:00 --- info: Downloaded 8000 rows and used 5012568 bytes of memory 
2009-10-07 17:44:41 -04:00 --- info: Downloaded 9000 rows and used 5197872 bytes of memory 
2009-10-07 17:44:42 -04:00 --- info: Downloaded 10000 rows and used 5393344 bytes of memory 
2009-10-07 17:44:43 -04:00 --- info: Downloaded 11000 rows and used 5588736 bytes of memory 
2009-10-07 17:44:43 -04:00 --- info: Downloaded 12000 rows and used 5753560 bytes of memory 
2009-10-07 17:44:44 -04:00 --- info: Downloaded 13000 rows and used 5918304 bytes of memory 
2009-10-07 17:44:45 -04:00 --- info: Downloaded 14000 rows and used 6103488 bytes of memory 
2009-10-07 17:44:46 -04:00 --- info: Downloaded 15000 rows and used 6268256 bytes of memory 
2009-10-07 17:44:46 -04:00 --- info: Downloaded 16000 rows and used 6443152 bytes of memory 
2009-10-07 17:44:47 -04:00 --- info: used 6597552 bytes of memory 

// This is after unsetting the variable. Didn't make a difference because garbage 
// collection had not run 
2009-10-07 17:44:47 -04:00 --- info: used 6598152 bytes of memory 

我希望有某種標準技術,用於處理(甚至更大)大的結果集這樣的,但我的研究沒有發現任何東西。

想法?

下面是一些代碼,通過要求:

$results = mysql_query($query); 

    Kohana::log('info', "used " . memory_get_usage() . " bytes of memory");     

    $first = TRUE; 
    $row_count = 0; 

    while ($row = mysql_fetch_assoc($results)) { 
     $row_count++; 
     $new_row = $row; 

     if (array_key_exists('user_id', $new_row)) { 
      unset($new_row['user_id']); 
     } 

     if ($first) { 
      $columns = array_keys($new_row); 
      $columns = array_map(array('columns', "title"), $columns); 
      echo implode(",", array_map(array('Reports_Controller', "_quotify"), $columns)); 
      echo "\n"; 
      $first = FALSE; 
     } 

     if (($row_count % 1000) == 0) { 
      Kohana::log('info', "Downloaded $row_count rows and used " . memory_get_usage() . " bytes of memory");     
     } 

     echo implode(",", array_map(array('Reports_Controller', "_quotify"), $new_row)); 
     echo "\n"; 
    } 
+0

只是好奇:爲什麼要使用$ NEW_ROW而不是使用$直接排? – Steve 2009-10-09 01:48:09

+0

從我處理ORM的一些結果時,這不是一個真正的數組,我不得不將其複製到數組中,以便刪除元素。 – Rafe 2009-10-09 04:47:16

回答

2

一些進一步的分析表明,問題是內存泄漏的地方。我將代碼分解爲最簡單的形式,每次迭代都不會增加內存使用量。我懷疑它是Kohana(我正在使用的框架)。

0

這是一個 「活」 的下載?我的意思是,當你生成CSV時,會將此推送給客戶端?如果是這樣,那麼你可以做一些事情:

  1. 不要使用輸出緩衝。這將所有內容保存在內存中,直到您明確或隱式刷新(通過腳本結尾),這將使用更多的內存;
  2. 當您從數據庫中讀取行時,將它們寫入客戶端。

除此之外,我們可能需要看到一些骨骼代碼。

+0

我同意。 flushflushflushflushflush – 2009-10-08 04:07:18

+0

我試過讓PHP自動處理緩衝並手動管理緩衝。 (據我所知,PHP不會默認緩衝輸出。)手動管理緩衝區會增加內存使用量。 – Rafe 2009-10-08 05:18:01

0

你居然定期刷新數據?由於MySQL客戶端,變量和輸出系統之間有多個數據副本,所以PHP的正常緩衝對於長時間運行的代碼來說可能非常惡劣。這是一個幾年,但我最後記得用類似這樣的框架代碼:

ob_end_flush() 
mysql_unbuffered_query() 
while ($row = mysql_fetch…) { 
    … do something … 

    flush(); // Push to Apache 
    unset($row, … all other temporary variables …); 
} 
+0

在每次迭代之後刷新緩衝區並取消設置我的臨時變量不會影響內存使用情況。 – Rafe 2009-10-08 14:59:10

+0

另一個要嘗試的方法是:您是否嘗試將行處理器放入函數中?一些搜索表明,PHP至少在歷史上並不總是清除內存,直到函數返回。 – 2009-10-09 02:48:48

0

感謝您的使用問題mysql_unbuffered_query()解決了我的用完了PHP與MySQL的大數據集工作RAM的問題。

PHP致命錯誤:用盡134217728個字節允許內存大小(試圖分配32個字節)/content/apps/application_price.php在線25