Проблема с выделением памяти в php

401
20 июля 2021, 09:00

Не могу разобраться со следующей проблемой. Требуется выгрузить из базы данных большую таблицу в 40к строк, но столкнулся с проблемой:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) line 58

Выгрузить нужно в html, таблица должна быть отображена и потом должна быть возможность сохранения в Excel. Для отображения использую Vue + axios.

Использование ini_set('memory_limit', '-1') помогло, но я всё таки думаю, что я что то не так делаю с памятью, прошу помощи более опытных людей. Ошибка проявляется на цикле while

Пример кода:

$c = oci_parse($oci_connect, $query);
$data = array();
$data = file_get_contents("php://input");
json_encode($data, true);
$json = json_decode($data, true);
/*$id1 = $json['sel1'];
$id2 = $json['sel2'];
$id3 = $json['sel_ch'];*/
$id1 = null;
$id2 = 201906;
$id3 = 143729749;
oci_bind_by_name($c, ':filial_ID', $id1);
oci_bind_by_name($c, ':period', $id2);
oci_bind_by_name($c, ':sale_channel_id', $id3);
oci_execute($c);
/*if ( ! oci_execute($c)) {
    $oci_error = oci_error($c);
    die($oci_error["message"]);
}*/

//ini_set('memory_limit', '-1');
$stack = array();
echo memory_get_usage();
while (($row = oci_fetch_row($c)) != false) {
    array_push($stack, $row);
    //echo json_encode($row, true);
    /*print_r ($row);
    unset($row);*/
}
echo json_encode($stack, true);
echo memory_get_usage();
/*oci_fetch_all($c, $res);
echo json_encode($res, true);*/
oci_close($oci_connect);
Answer 1

Данные занимают память, если данных много, они занимают много памяти. Как получить большой объём данных, не загружая их все в оперативную память? Можно выводить (в файл, стандартный вывод, в html-таблицу в браузере пользователя) данные кусками. Загрузить, скажем, 1000 строк, вывести, снова 1000 и так далее, пока не получится 40к.

В конкретно вашем случае вы взаимодействуете со своим пхп-скриптом по HTTP и можно отправить один запрос на 1000 строк, следующий запрос на следующую 1000! Это и называют пагинацией (постраничным выводом).

В результате можно напихать пользователю в браузер все 40к строк. И тут вы удивитесь. Теперь память начнёт жрать браузер! Кроме того ни один нормальный человек не сможет изучать все 40к строк и делать какие-то полезные выводы. Выходит, что и в браузер не надо совать все 40к, а надо нарисовать пользователю кнопочку "Показть ещё" или список страниц.

Если вы решите создать excel-файл из 40к строк, то заметите что и экселю может стать плоховато. Но если вы всё-таки решитесь, то вам опять-таки не надо вытаскивать сразу 40к, пишите файл строка за строкой (csv, например) и не сохраняйте сроки из базы в массив.

Answer 2

Переменная $stack занимает слишком много места в памяти. Попробуйте вывести данные без предварительной записи в массив. Как-то так:


ob_start();
echo "[";
$isFirst = true;
while (($row = oci_fetch_row($c)) != false) {
    echo ($isFirst ? '' : ','), json_encode($row, true);
    $isFirst = false;
}
echo "]";
ob_end_flush();
READ ALSO
Автоматическая генерация миниатюр wordpress

Автоматическая генерация миниатюр wordpress

При загрузке изображений и публикации записей миниатюры не создаютсяПри попытке получить миниатюру - получаю фулл сайз

243
Ошибка Cannot declare class в Symfony 4 при создании своей bundle

Ошибка Cannot declare class в Symfony 4 при создании своей bundle

Пытаюсь создать свой bundle для многократного использованияСовершенно непредсказуемым образом вылетает ошибка:

228
Подгрузка товаров при клике, woocommerce

Подгрузка товаров при клике, woocommerce

На странице магазина /shop выводится список всех товаровКак сделать, чтобы выводилось сначала определённое количество товаров, допустим 4, и ниже...

197
Сортировка в GridView по динамическому полю

Сортировка в GridView по динамическому полю

Теперь модель имеет не 3 свойства a 4

165