Intereting Posts
Magento – Пользовательский платежный модуль Как предотвратить инъекции SQL путем обновления кодов сортировать коллекцию Magento ПОСЛЕ загрузки Углерод – получить первый день месяца Как вызвать функцию JavaScript из PHP? Правильное экранирование полей и параметров запроса при использовании PDO Отправка данных, таких как целые числа и текстовые строки, из телефона в веб-базу данных Алгоритмы для сходства строк (лучше, чем у Левенштейна и аналогичного текста)? Php, Js как я могу использовать preg_match с буквенно-цифровым и уникодным приемом? Получить все дочерние, внуки и т. Д. Узлы под родителями, используя php с результатами запроса mysql Собрать $ _POST из нескольких блоков флажков Объедините результаты двух запросов PDO Обновление нескольких строк сразу в PHP PHP date_default_timezone_set () Восточное стандартное время (EST) Как документировать REST API на основе Symfony (аналогично возможностям документации enunciate)

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

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

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

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

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

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

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

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

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

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

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

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

PDO для Postgres использует внутренние курсоры .

По-видимому, 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.