PHP не хватает памяти, несмотря на ограничение и компенсацию запросаPhp

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 PHP не хватает памяти, несмотря на ограничение и компенсацию запроса

Сообщение Anonymous »

Справочная информация
Необработанный SQL-запрос со множеством объединений, выборок и прочего при загрузке

Код: Выделить всё

$results = DB::SELECT($query)
создает коллекцию $results объемом около 500 МБ и 450 000 элементов, что является "неправильным".
Решение
Решение
strong>
Поэтому вместо этого $query теперь создает временную таблицу, к которой запрашивается следующее:

Код: Выделить всё

$new_rows = true;
$chunk = 25000;
$offset = 0;

while ($new_rows) {
$chunked_results = DB::SELECT('SELECT * FROM tmp_table ORDER BY id DESC LIMIT ' . $chunk . ' OFFSET ' . $offset );

if (count($chunked_results) === 0) {
$new_rows = false;
}

foreach ($chunked_results as $row) {
//Do stuff with $row
}

$offset+= $chunk;
unset($chunked_results);
}
Проблема[/b]
Несмотря на снятие настроек $chunked_results после каждого запроса, моему скрипту по-прежнему не хватает памяти в районе 75-тысячного ряда - почти тоже самое нет. строк, которые были загружены без фрагментации/tmp_table.
Это заставляет меня поверить, что каким-то образом содержимое предыдущих $chunked_results сохраняется в памяти и на самом деле не сбрасывается, или DB::class запоминает данные в фоновом режиме.
Выполнение DB::RECONNECT('mysql') уничтожает временную таблицу :(
Решение
После применения рекомендаций из комментариев и перемещения объектов код, запрашивающий временную таблицу, теперь выглядит следующим образом:

Код: Выделить всё

$new_rows = true;
$chunk = 25000;
while ($new_rows) {
$results = DB::SELECT('SELECT * FROM elem_inter.temp_argpremrachrambaexport_' . $this->userId . (isset($last_id) ? (' WHERE idRac < ' . $last_id) : ('')) .' ORDER BY idRac DESC LIMIT ' . $chunk);

if (count($results) !== 0) {
foreach ($results as $row) {
//Do stuff with rows
}
$last_id = $results[array_key_last($results)]->idRac;
} else {
$new_rows = false;
}
}
В целях тестирования я добавил это в контроллер:

Код: Выделить всё

function sizeOfVar($var) {
$start_memory = memory_get_usage();
$tmp = unserialize(serialize($var));
return memory_get_usage() - $start_memory;
}
и использовал его следующим образом:

Код: Выделить всё

while ($new_rows) {
$results = DB::SELECT('SELECT * FROM elem_inter.temp_argpremrachrambaexport_' . $this->userId . (isset($last_id) ? (' WHERE idRac < ' . $last_id) : ('')) .' ORDER BY idRac DESC LIMIT ' . $chunk);
$results_memory_usage = $this->sizeOfVar($results);
...
С нетерпением ожидая подтверждения того, что переменная $results вышла из-под контроля, я установил точку останова на if (count($chunked_... и запустил скрипт. Однако переменная $results не только не вышла из-под контроля, но и скрипт не аварийно завершился! В php_errors.log не было ошибки «недостаточно памяти».
Я решил не публиковать это в качестве ответа, так как до сих пор понятия не имею, почему он решил начать работать после проверки объема памяти, и еще меньше понятия, почему он продолжает работать после удаления всего sizeOfVar ($var) и ссылка на нее в коде...
Если у кого-то есть представление о том, что здесь происходит, просветите меня. Лучшее предположение:
Изображение


Подробнее здесь: https://stackoverflow.com/questions/791 ... ting-query
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Php»