Лучшая практика для перебора набора результатов в Postgres / PHP / PDO? - PullRequest
1 голос
/ 24 октября 2011

Я использую PHP 5.3.6 с PDO для доступа к Postgres 9.0.4.Меня попросили уменьшить объем памяти отчета.Текущая реализация проста: выполнить запрос, выполнить fetchAll (), а затем выполнить итерацию с foreach () через полученный массив.Это, очевидно, не масштабируется с огромными результирующими наборами: он может временно потреблять 100 МБ или более.

У меня есть новая реализация, которая берет дескриптор оператора PDO, а затем выполняет итерации непосредственно с помощью foreach (), то есть без промежуточногомассив через fetchAll ().(Из того, что я прочитал, повторяется дескриптор оператора с вызовами foreach fetch () под прикрытием.) Это так же быстро и потребляет в меньше памяти: около 28 КБ.Тем не менее, я не уверен, что я делаю это правильно, потому что, хотя я сделал тонну Google, трудно найти ответы на основные вопросы по этому поводу:

  • I 'Я видел статьи, которые предлагают решить мою первоначальную проблему с помощью курсоровДрайвер Postgress PDO уже использует курсоры внутри?Если требуется написать собственный SQL для создания курсора, я готов, но я бы предпочел написать самый простой код (но не проще!).

  • Если вызов foreachfetch () каждая итерация, разве это не слишком болтливый по сети?Или он умный и выбирает много строк одновременно, например, 500, чтобы сэкономить пропускную способность?(Это может означать, что он использует курсоры внутри.)

  • Я видел статью, которая оборачивает дескриптор оператора в классе, который реализует интерфейс Iterator.Разве это не избыточно, учитывая, что дескриптор оператора PDO уже делает это?Или я что-то упустил?

  • Мой вызов для подготовки оператора SQL выглядит следующим образом:

    $ sth = $ dbh-> prepare ($ sql);

Я обнаружил, что это не сказалось на разнице в памяти и скорости, если я сделал это:

$sth = $dbh->prepare($sql, array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );

Это потому, что это драйвер по умолчанию для драйвера Postgres PDO?Это имело бы смысл, если оно уже использует курсоры внутри.

Приветствуются общие комментарии о подходе и других способах решения этой проблемы.

Ответы [ 2 ]

1 голос
/ 24 октября 2011
0 голосов
/ 20 мая 2014

Видимо PDO::CURSOR_FWDONLY не использует курсоры.Тесты черного ящика:

(0) Подготовка:

$con = new \PDO('dsn');
// you'll get "NO ACTIVE TRANSACTION" otherwise
$con->beginTransaction();

$sql = 'select * from largetable';

(1) По умолчанию - длится вечно:

$stmt = $con->prepare($sql);
$stmt->execute();
print_r($stmt->fetch());

(2) FWDONLY - длится вечно:

$stmt = $con->prepare($sql, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY));
$stmt->execute();
print_r($stmt->fetch());

(3) SCROLLABLE - запускается во флэш-памяти:

$stmt = $con->prepare($sql, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_SCROLL));
$stmt->execute();
print_r($stmt->fetch());

Я включил ведение журнала PG, просто чтобы быть уверенным, и это действительно так - только SCROLL использует курсоры.

Итак, единственный способ использовать курсоры - это использовать SCROLL, по крайней мере, в PHP 5.4.23.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...