Действительно ли возможно циклично выполниться через запрос так, чтобы, если (например), 500 000 строк найдены, это возвратило результаты для первых 10,000 и затем повторно выполнило запрос снова?
Так, что я хочу сделать, выполняется запрос, и создайте массив, как это:
$result = pg_query("SELECT * FROM myTable");
$i = 0;
while($row = pg_fetch_array($result) ) {
$myArray[$i]['id'] = $row['id'];
$myArray[$i]['name'] = $row['name'];
$i++;
}
Но, я знаю, что будут несколько сотен тысяч строк, таким образом, я хотел сделать это в пакетах подобных 10,000... 1 - 9,999 и затем 10 000 - 10 999 и т.д... Причина, почему то, потому что я продолжаю получать эту ошибку:
Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 3 bytes)
Который, несущественно, я не понимаю, как 3 байта могли исчерпать 512M... Так, если это - что-то, что я могу просто изменить, это было бы большим, хотя, все еще могло бы быть лучше, чтобы сделать это в пакетах?
Эти последние 3 байта были соломинкой, которая сломала спину верблюду. Вероятно, попытка выделения в длинной строке распределений, приведшая к сбою.
К сожалению, libpq
попытается полностью кэшировать наборы результатов в памяти перед передачей управления приложению. Это в дополнение к той памяти, которую вы используете в $ myArray
.
Было предложено использовать LIMIT ... OFFSET ...
, чтобы уменьшить размер памяти; этот будет работать, но неэффективен , поскольку он может без нужды дублировать усилия по сортировке на стороне сервера каждый раз, когда запрос будет повторно выдан с другим смещением (например, чтобы ответить LIMIT 10 OFFSET 10000
, Postgres все равно придется отсортировать весь набор результатов, только чтобы вернуть строки 10000..10010.)
Вместо этого используйте DECLARE ...CURSOR
для создания серверного курсора , за которым следует FETCH FORWARD x
для выборки следующих x
строк. Повторяйте столько раз, сколько необходимо, или пока не будет возвращено меньше x
строк. Не забудьте нажать CLOSE
курсор, когда вы закончите, даже когда / если возникнет исключение.
Кроме того, не SELECT *
; если вам нужны только id
и name
, создайте курсор FOR SELECT id, name
(в противном случае libpq
без необходимости извлекает и кеширует столбцы, которые вы никогда не использовать, увеличивая объем памяти и общее время запроса.)
Используя курсоры, как показано выше, libpq
будет удерживать не более x
строк в памяти одновременно. Однако убедитесь, что вы также очистили свой $ myArray
между FETCH
es, если это возможно, иначе у вас все равно может не хватить памяти из-за $ myArray
.
Сервер PostgreSQL кэширует результаты запроса до тех пор, пока вы их не получите, поэтому добавление их в массив в таком цикле приведет к исчерпанию памяти, несмотря ни на что. Либо обрабатывайте результаты по одной строке за раз, либо проверяйте длину массива, обрабатывайте полученные результаты и затем очищайте массив.
Ошибка означает, что PHP пытается выделить 3 байта, но вся доступная часть 512MB меньше 3 байт.
Даже если вы делаете это партиями, в зависимости от размера результирующего массива вы все равно можете исчерпать доступную память.
Возможно, вам действительно не нужно получать все записи?