Столкнулся со следующей проблемой. Код:
$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 миллионов нужно будет проделать то-же самое.
Если одним запросом вытащить все данные, то на данные не хватит памяти.
Логика - получаю кол-во всех записей, разбиваю на небольшие запросы по несколько (в данном случае 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
можно кешировать выборку в 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). всё таки я бы предпочёл кэширование запросов, но по сути можно и всё совместить.
при 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) |
Смысл всего этого был в том, чтобы изменить значение одного поля для всей таблицы, на основе данных из этой таблицы и еще одной (произвести некоторый расчет для каждой записи и занести его в таблицу). Собственно, проблему решил тем, что просто написал один большой запрос. |
Разобрался - и хорошо. А я бы сделал именно триггерную функцию. В данном случае она очень даже подходит. Повесил бы триггер на апдейт. Кстати говоря, даже уже так делал.
И ничего, на самом деле, менять не нужно
