Распределить память в PHP - PullRequest
       2

Распределить память в PHP

1 голос
/ 10 сентября 2010

У меня есть скрипт, который переносит около 1,5 миллионов строк (данных ~ 400 МБ) из таблицы в другую таблицу (во время этого процесса некоторые данные преобразуются, модифицируются и помещаются в правильное поле). Это простой скрипт, он просто рекурсивно загружает данные, а затем помещает их в новые таблицы в правильных полях и форматах. Сценарии работают (в качестве примера), вытаскивая всех пользователей из таблицы, затем начинает циклически проходить через пользователей, вставляя их в новую таблицу, затем вытягивая все сообщения от этого пользователя, просматривая и вставляя их в правильную таблицу затем извлеките все комментарии из поста и вставьте их, затем перепрыгните назад и перетащите все контакты для этого пользователя, наконец, на следующего пользователя, где он проходит тот же процесс.

У меня просто проблема с огромным объемом передаваемых данных, потому что он настолько велик, и в PHP нет никакого управления памятью, кроме сборки мусора (которую я знаю), я не могу завершить сценарий (он проходит через около 15 000 подключений и элементов, переданных до того, как он исчерпает память объемом 200 МБ).

Это единовременно, поэтому я делаю это на своем локальном компьютере, а не на реальном сервере.

Поскольку unset () на самом деле не освобождает память, есть ли другой способ освободить данные в переменной? Одна вещь, которую я попытался сделать, это переписать переменную в значение NULL, но это, похоже, не помогло.

Любой совет был бы потрясающим, потому что, мужик, это воняет.

Ответы [ 2 ]

5 голосов
/ 10 сентября 2010

Если вы на самом деле делаете это рекурсивно, тогда это ваша проблема - вы должны делать это итеративно.Рекурсивная обработка оставляет накладные расходы (+ мусор) при каждом следующем вызове - так что в итоге вы достигнете предела.Итеративный подход не имеет таких проблем и должен активно собирать мусор.

Вы также говорите о том, какое количество связей просто ошеломляет - почему их так много?Думаю, я не совсем понимаю ваш процесс и почему нужен именно этот подход, а не одно соединение извлечения и одно соединение магазина.Даже если вы - скажем - переподключение для каждой строки, вам следует рассмотреть возможность использования постоянных соединений, которые позволяют второму соединению с той же БД повторно использовать последнее соединение.Постоянные соединения не являются отличной идеей для веб-приложения с несколькими пользователями (по соображениям масштабируемости), но в вашем очень целенаправленном случае они должны подойти.

1 голос
/ 10 сентября 2010

unset() освобождает память, но только если не удаляемый объект не имеет других ссылок, указывающих на него.Поскольку PHP использует подсчет ссылок, а не «реальный» GC, это может укусить вас, если у вас где-то есть циклические ссылки - типичный виновник находится внутри ORM, где у вас часто есть объект Database, который содержит ссылки на некоторые Table объекты,и каждый объект Table имеет ссылку обратно на Database.Даже если никакая внешняя ссылка не существует ни на один объект, они все равно ссылаются друг на друга, предотвращая попадание счетчика ссылок в ноль.

Кроме того, обе таблицы находятся в одной базе данных?Если это так, то все, что вам нужно, может быть простым INSERT ... SELECT запросом, отображением столбцов и выполнением небольшого преобразования на лету (хотя обработка, которую вам нужно выполнить, может быть невозможна или невозможна в SQL).

Кроме этого, вам не нужно так много подключений.Просто откройте один для читателя, один для писателя;подготовить оператор для писателя, выполнить запрос читателя, извлечь по одной строке за раз (это важно: не извлекать их все сразу) из запроса читателя, выполнить обработку, вставить его в подготовленный оператор писателя, промыть иповторение.Использование памяти PHP должно оставаться примерно постоянным после первых нескольких строк.

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