Пост-ГРЭС - выполнить запрос в пакетах?

Действительно ли возможно циклично выполниться через запрос так, чтобы, если (например), 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... Так, если это - что-то, что я могу просто изменить, это было бы большим, хотя, все еще могло бы быть лучше, чтобы сделать это в пакетах?

5
задан Milen A. Radev 28 March 2010 в 11:46
поделиться

4 ответа

Вы можете использовать LIMIT (x) и OFFSET (y)

3
ответ дан 14 December 2019 в 01:05
поделиться

Эти последние 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 .

6
ответ дан 14 December 2019 в 01:05
поделиться

Сервер PostgreSQL кэширует результаты запроса до тех пор, пока вы их не получите, поэтому добавление их в массив в таком цикле приведет к исчерпанию памяти, несмотря ни на что. Либо обрабатывайте результаты по одной строке за раз, либо проверяйте длину массива, обрабатывайте полученные результаты и затем очищайте массив.

0
ответ дан 14 December 2019 в 01:05
поделиться

Ошибка означает, что PHP пытается выделить 3 байта, но вся доступная часть 512MB меньше 3 байт.

Даже если вы делаете это партиями, в зависимости от размера результирующего массива вы все равно можете исчерпать доступную память.

Возможно, вам действительно не нужно получать все записи?

0
ответ дан 14 December 2019 в 01:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: