У меня есть php-скрипт, который запускает mysql-запрос, а затем обрабатывает результат, и в этом цикле также выполняется несколько запросов:
$sqlstr = "SELECT * FROM user_pred WHERE uprType != 2 AND uprTurn=$turn ORDER BY uprUserTeamIdFK"; $utmres = mysql_query($sqlstr) or trigger_error($termerror = __FILE__." - ".__LINE__.": ".mysql_error()); while($utmrow = mysql_fetch_array($utmres, MYSQL_ASSOC)) { // some stuff happens here // echo memory_get_usage() . " - 1241<br/>\n"; $sqlstr = "UPDATE user_roundscores SET ursUpdDate=NOW(),ursScore=$score WHERE ursUserTeamIdFK=$userteamid"; if(!mysql_query($sqlstr)) { $err_crit++; $cLog->WriteLogFile("Failed to UPDATE user_roundscores record for user $userid - teamuserid: $userteamid\n"); echo "Failed to UPDATE user_roundscores record for user $userid - teamuserid: $userteamid<br>\n"; break; } unset($sqlstr); // echo memory_get_usage() . " - 1253<br/>\n"; // some stuff happens here too }
Запрос на обновление никогда не завершается.
По какой-то причине между двумя вызовами memory_get_usage
добавляется некоторая память. Поскольку большой цикл работает около 500 000 или более раз, в конце концов, это действительно добавляет к большому количеству памяти. Здесь что-то не хватает?
могло ли быть возможно, что память фактически не добавляется между двумя вызовами, но в другой точке сценария?
Изменить: дополнительная информация: перед циклом он составляет около 5 мб, после цикла около 440 Мб, и каждый запрос на обновление добавляет около 250 байт. (остальная часть памяти добавляется в другие места цикла). Причина, по которой я больше не писал больше о «других вещах», – это то, что около 300 строк кода. Я опубликовал эту часть, потому что это похоже на то, где добавляется большая часть памяти.
Эта утечка памяти будет проблемой только в том случае, если она уничтожит сценарий с ошибкой «исчерпанной памяти». PHP будет с удовольствием собирать любые необычные объекты / переменные самостоятельно, но коллекционер не будет пинать до тех пор, пока он не понадобится – сбор мусора может быть очень дорогой операцией.
Это нормально, когда вы видите увеличение использования памяти, даже если вы постоянно используете одни и те же объекты / переменные – это происходит только тогда, когда использование памяти превысит определенный уровень, который собиратель будет запускать и чистить дома.
Я подозреваю, что вы можете заставить все работать намного быстрее, если вы собрали идентификаторы пользователей в группы и выпустили меньше обновлений, каждый раз меняя записи. например, выполните следующие действия:
UPDATE user_roundscores SET ursUpdDate=NOW() WHERE ursUserTeamIdFK IN (id1, id2, id3, id4, id5, etc...)
вместо того, чтобы делать это одно обновление для пользователя. Меньшее количество раундов через уровень интерфейса DB и больше времени на сервере = более быстрый запуск.
Кроме того, рассмотрите влияние теперь расширения этого на миллионы пользователей, как вы говорите в комментарии. У миллиона отдельных обновлений потребуется нетривиальное количество времени для запуска, поэтому NOW()
не будет «константой». Если для полного запуска требуется 5 минут, то вы получите большое количество ursUpdDate
меток ursUpdDate
. Возможно, вы захотите рассмотреть кеширование одного вызова NOW()
в переменной на стороне сервера и выпустить обновления для этой переменной:
SELECT @cachednow :p NOW(); UPDATE .... SET ursUpDate = @cachednow WHERE ....;
Лучший способ – это, вероятно, получить все userIds и слить их в файл. Затем запустите новый скрипт, который вилки с трубами на x количество рабочих дронов. Затем просто дайте им небольшой список userIds для обработки по мере их завершения. С несколькими процессорами / ядрами / серверами вы можете быстрее завершить задачу. Если один работник не работает, просто запустите новый. Чтобы использовать другие серверы в качестве рабочих, вы можете вызвать их с помощью curl / fopen / soap / etc из рабочего потока.
Я думаю, вы должны попробовать вызвать – Из комментариев: mysql_free_result()
в какой-то момент цикла.
Стоит отметить, что mysql_query () возвращает ресурс только для запросов
SELECT
,SHOW
,EXPLAIN
иDESCRIBE
.
Таким образом, нет никакого результата для бесплатного запроса на обновление.
Во всяком случае, ваш подход не самый лучший для начала. Вместо этого попробуйте mysqli paramterized statements или (даже лучше) обновить строки в базе данных напрямую. Похоже, что все SQL в цикле могут обрабатываться одним оператором UPDATE.
Одной из причин, по которым вы можете видеть дополнительную используемую память на каждой итерации, является то, что PHP не (пока) мусор собрал вещи, на которые больше не ссылаются.
Из руководства php.net memory_get_usage :
параметры
real_usage Установите для этого значение ИСТИНА, чтобы получить реальный размер памяти, выделенной из системы. Если не задано или FALSE, сообщается только память, используемая emalloc ().
Когда этот параметр установлен в true, сценарий не показал увеличения памяти, как я и ожидал.
unset
вызов бессмыслен / неактивен. Попробуйте с mysql_free_result
хотя это может иметь некоторый эффект.