[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Утечка памяти
egor111
Здравствуйте.
Столкнулся со следующей проблемой. Код:

$countQuery = 'SELECT COUNT(*) FROM table1';
$count = $connection->GetField($countContractsQuery);

$page = 1;
$perPage = 10000;

$previosLimit = 0;

for ($j = 1; $j <= $count; $j++)
{
$page = ceil($j / $perPage);
if ( ceil(($j+1) / $perPage) > $page || ($j+1) >= $count )
{
if ( ($j+1) >= $count )
$query = 'SELECT * FROM table1 LIMIT '.$previosLimit.','.$count;
else
$query = 'SELECT * FROM table1 LIMIT '.$previosLimit.','.$j;

$resArr = array();
$result = mysql_query($query, $connection->getDbLink());
$row = null;
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
$resArr[] = $row;
}
$row = null;
unset($result);
echo memory_get_peak_usage(1). '<br>';

unset($resArr);
$previosLimit = $j;
}
}


Собственно, код выбирает кол-во всех данных из одной таблицы, разбивает и его на LIMIT. Данных очень много.
Проблема в следующем. Допустим, у нас 43 тысячи записей в table1.
В таком случае вывод на экран будет примерно таким (потребление памяти скриптом):
10 000 000
18 000 000
26 000 000
35 000 000
Скажите, пожалуйста, куда утекает память?
Если будет больше записей (как оно и есть), то скрипту просто не хватит памяти для выполнения.
Как с этим можно бороться?



Спустя 13 минут, 41 секунда (19.05.2012 - 16:30) Nikitian написал(а):
Попробуйте добавить после обработки запросов mysql_freee-result()

Спустя 5 минут, 49 секунд (19.05.2012 - 16:36) egor111 написал(а):
Спасибо за ответ, но увы, не помогло. Результат остался тем же.

Спустя 48 минут, 6 секунд (19.05.2012 - 17:24) Sergen написал(а):
egor111 а как Вы вычисляете потребление памяти?

Спустя 6 минут, 52 секунды (19.05.2012 - 17:30) egor111 написал(а):
echo memory_get_peak_usage(1). '<br>';

Спустя 15 минут, 22 секунды (19.05.2012 - 17:46) forza написал(а):
Не совсем понял логику скрипта. Но мне кажется, что проблема тут в запросах в цикле. Может есть возможность сначало сгенерировать sql-запрос средствами ПХП, а потом уже 1 запросом вытащить все нужные данные?

Спустя 6 минут, 15 секунд (19.05.2012 - 17:52) egor111 написал(а):
Данных очень много.
Если одним запросом вытащить все данные, то на данные не хватит памяти.
Логика - получаю кол-во всех записей, разбиваю на небольшие запросы по несколько (в данном случае 10000) строк (LIMIT 0,10000 , LIMIT 10000, 20000). Это делаю для того, чтобы получать данные порциями, которые уместятся в памяти.
В таблице 5 миллионов записей. Для таблицы в 15 миллионов нужно будет проделать то-же самое.

Спустя 20 минут, 32 секунды (19.05.2012 - 18:13) forza написал(а):
Т.е вам нужно будет вытащить 15 миллионов записей за раз и проделать с ними какие-то телодвижения?

Спустя 10 минут, 33 секунды (19.05.2012 - 18:23) egor111 написал(а):
Нет же. Я хочу вытаскивать 15 миллионов записей порциями, скажем по 100000, и проделывать с ними какие-то телодвижения. Для этого я и сделал запросы с LIMIT в цикле. Эти запросы и будут давать мне небольшие порции данных, которые не должны переполнять память.
К слову, это будет сделано всего один раз (ну это чтобы не кидали в меня тухлыми помидорами).

Спустя 17 минут, 9 секунд (19.05.2012 - 18:40) Zerstoren написал(а):
Заюзайте xdebug, увидите, где именно теряется память.

Спустя 1 час, 10 минут, 2 секунды (19.05.2012 - 19:50) Игорь_Vasinsky написал(а):
while() кажется быстрее и удобней

можно кешировать выборку в memcache

Спустя 1 час, 11 минут, 16 секунд (19.05.2012 - 21:02) sergeiss написал(а):
Цитата (egor111 @ 19.05.2012 - 18:23)
Нет же. Я хочу вытаскивать 15 миллионов записей порциями, скажем по 100000, и проделывать с ними какие-то телодвижения. Для этого я и сделал запросы с LIMIT в цикле. Эти запросы и будут давать мне небольшие порции данных, которые не должны переполнять память.
К слову, это будет сделано всего один раз (ну это чтобы не кидали в меня тухлыми помидорами).

А какие именно "телодвижения" надо сделать с этими данными? Быть может, проще будет сделать функцию внутри БД, которая это всё сделает, и не напрягать ПХП без необходимости?

Можно сделать не просто функцию, а триггерную функцию, которая проделает то, что надо.

В любом случае для более подробной рекомендации надо знать, что же ты хочешь сделать.

PS. Использование LIMIT без использования ORDER BY в выборке может привести к тому, что обработаны будут не все данные, в то время, как некоторые будут обработаны многократно.
Так что триггерная функция тут будет наиболее верным решением.

Спустя 2 минуты, 9 секунд (19.05.2012 - 21:04) Игорь_Vasinsky написал(а):
ты говоришь про хранимые процедуры?

Спустя 3 минуты, 55 секунд (19.05.2012 - 21:08) sergeiss написал(а):
Цитата (Игорь_Vasinsky @ 19.05.2012 - 21:04)
ты говоришь про хранимые процедуры?

Вобщем, да. Только в Мускуле есть такое разделение, как "процедуры" и "функции", в то время как в Постгре говорится только про "функции". Но суть одна и та же, вобщем-то.

Спустя 12 минут, 4 секунды (19.05.2012 - 21:20) Игорь_Vasinsky написал(а):
у него запросы в цикле. тут либо пересмотреть структуру БД - нормализовать или денормализовать.

при 15 миллионов записаей, хоть и с пагинатором (LIMIT). всё таки я бы предпочёл кэширование запросов, но по сути можно и всё совместить.

Спустя 9 минут, 35 секунд (19.05.2012 - 21:29) sergeiss написал(а):
Цитата (Игорь_Vasinsky @ 19.05.2012 - 21:20)
у него запросы в цикле

Так.. Этаааааа.... Я про то и говорю, что ВСЁ ЭТО НАФИГ НЕ НУЖНО!!! Никакие запросы в цикле не нужны. А надо сделать всю хрень, по возможности, внутри БД. Посредством триггерной функции.

Спустя 16 минут, 24 секунды (19.05.2012 - 21:46) Игорь_Vasinsky написал(а):
ааа... я в своей приктике пока не видел необходимости в использовании всего этого, поэтому понял поверхностно.

Спустя 9 часов, 45 минут, 33 секунды (20.05.2012 - 07:31) egor111 написал(а):
Смысл всего этого был в том, чтобы изменить значение одного поля для всей таблицы, на основе данных из этой таблицы и еще одной (произвести некоторый расчет для каждой записи и занести его в таблицу).
Собственно, проблему решил тем, что просто написал один большой запрос.
За ответы спасибо.
Но все же было бы интересно, на будущее, что же происходит.
Хотя даже в анголонете нет ответов на этот вопрос.

Спустя 3 часа, 55 минут, 49 секунд (20.05.2012 - 11:27) sergeiss написал(а):
Цитата (egor111 @ 20.05.2012 - 07:31)
Смысл всего этого был в том, чтобы изменить значение одного поля для всей таблицы, на основе данных из этой таблицы и еще одной (произвести некоторый расчет для каждой записи и занести его в таблицу).
Собственно, проблему решил тем, что просто написал один большой запрос.

Разобрался - и хорошо. А я бы сделал именно триггерную функцию. В данном случае она очень даже подходит. Повесил бы триггер на апдейт. Кстати говоря, даже уже так делал.
И ничего, на самом деле, менять не нужно smile.gif Пишем в апдейте, что какое-то поле равно самому себе. То есть, реальные данные не меняем. Но при этом, тем не менее, будет проведен апдейт.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.