Экономия памяти при извлечении больших наборов результатов с PDO - PullRequest
1 голос
/ 02 июля 2010

Я написал инструмент для репликации базы данных на PHP. Работает нормально, но есть одна проблема:

Я использую PDO для подключения к различным базам данных, чтобы сохранить его независимым от какой-либо конкретной СУБД, что крайне важно для этого приложения.

Инструмент выполняет некоторый анализ таблиц, чтобы решить, как преобразовать определенные типы и некоторые другие вещи. Затем он делает "SELECT * FROM <tablename>", чтобы получить строки, которые нужно скопировать. Результирующие наборы довольно большие (около 50 тыс. Строк в некоторых таблицах).

После этого он перебирает набор результатов в цикле while с PDOStatement::fetch();, выполняет преобразование типов и экранирование, создает оператор INSERT и передает его в целевую базу данных.

Все это работает хорошо, за одним исключением. При извлечении строк по одному из набора результатов процесс PHP продолжает поглощать все больше и больше памяти. Я предполагаю, что PDO сохраняет уже обработанные строки в памяти, пока не будет обработан весь набор результатов.

Я также заметил, что когда мой инструмент заканчивает работу с одной таблицей и переходит к следующей, потребление памяти мгновенно падает, что поддерживает мою теорию.

Я НЕ храню данные в переменных PHP! Я держу только одну строку в любой момент времени для обработки, так что это не проблема.

Теперь к вопросу: есть ли способ заставить PDO не хранить все данные в памяти? Я обрабатываю только одну строку за раз, поэтому нет необходимости хранить весь этот мусор. Я действительно хотел бы использовать меньше памяти для этой вещи.

1 Ответ

2 голосов
/ 02 июля 2010

Я считаю, что проблема связана с сборщиком мусора в php, так как он не собирает мусор достаточно скоро.
Я бы попытался получить результаты в виде кусков row_count размера, например "SELCT ... LIMIT offset, row_count" в MySQL или "SELECT * FROM (SELECT ...) WHERE ROW_NUM BETWEEN offset AND (offset + row_count)" в ORACLE.
Используя Zend_Db_Select можно генерировать независимые от DB запросы:

$select = $db->select()
    ->from(array('t' => 'table_name'),
        array('column_1', 'column_2'))
    ->limit($row_count, $offset);
$select->__toString(); 
# on MySQL renders: SELECT column_1, column_2 FROM table_name AS t LIMIT 10, 20
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...