2009-10-08 5 views
4

Итак, у меня есть страница PHP, которая позволяет пользователям загружать CSV для того, что может быть целым рядом записей. Проблема в том, что чем больше результатов возвращает запрос MySQL, тем больше памяти он использует. Это не удивительно, но это создает проблему.Как ограничить использование памяти PHP при обработке запросов MySQL?

Я попытался использовать 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

+0

Это артефакт, когда я имел дело с некоторыми результатами ORM, которые не были реальным массивом, который мне пришлось копировать в массив, чтобы я мог удалять элементы. – Rafe

ответ

2

Некоторые дальнейшее профилирование показывает, что проблема утечки памяти где-то. Я разделил код на свою простую форму, и использование памяти не увеличивалось с каждой итерацией. Я подозреваю, что это Kohana (каркас, который я использую).

0

Является ли это "жить" скачать? Под этим я подразумеваю подталкивание этого к клиенту, когда вы генерируете CSV? Если да, то есть некоторые вещи, которые вы можете сделать:

  1. Не используйте буферизацию вывода. Это сохраняет все в памяти, пока вы не очистите его явно или неявно (по окончании скрипта), который будет использовать больше памяти;
  2. Когда вы читаете строки из базы данных, пишите их клиенту.

Кроме этого, нам, вероятно, необходимо увидеть код скелета.

+0

Согласен. flushflushflushflushflush –

+0

Я пробовал это, позволяя PHP обрабатывать буферизацию автоматически и вручную управлять буферизацией. (По умолчанию, по умолчанию, PHP не выводит вывод по умолчанию.) В ручном режиме управление буфером увеличивает использование памяти. – Rafe

0

Вы периодически очищаете данные? Обычная буферизация PHP может быть довольно порочной для долгого кода, поскольку между клиентом MySQL, вашими переменными и выходной системой имеется несколько копий данных. Прошло несколько лет, но я в последний раз напомнить, используя что-то вроде этого в скелет кода:

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

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

Промывка буфера и снятие моей временной переменной после каждой итерации не влияет на использование памяти. – Rafe

+0

Еще одна вещь, которую нужно попробовать: попытались ли вы превратить процессор строк в функцию?В некоторых поисковых запросах PHP, по крайней мере, исторически не всегда очищал память, пока функция не вернется. –

0

Спасибо за ваш вопрос, используя mysql_unbuffered_query(), решил мою проблему с запуском ОЗУ с PHP и MYSQL, работающими с большим набором данных.

PHP Фатальная ошибка: Разрешены памяти размером 134217728 байт исчерпаны (пытались выделить 32 байт) в /content/apps/application_price.php на линии 25

Смежные вопросы