graf_vorontsov
пытаюсь обработать файл, и после загрузить данные полученные из него в БД
12 206 610 строк, вес 608 мб
http://php.net/memory-limit увеличил до 700МБ не помогаетошибку такую выдаёт
Fatal error: Out of memory (allocated 460849152) (tried to allocate 460330898 bytes)
runcore
а что за файл?
в чем заключается обработка?если текстовый — то построчно читать нужно
если XML то потоковый парсер используй
artoodetoo
В PHP специфическое внутреннее представление данных, с большим оверхедом. Особенно если ты грузишь файл в массив строк или объект с кучей полей. Каждое атомарное значение сопровождается еще внутренним дескриптором. Для массива добавляются издержки на индексы. В общем «скорость в обмен на память» — вот девиз PHP
Измени алгоритм так, чтобы не понадобилось хранить целиком. Обрабатывай в цикле по записям, чтоли.
graf_vorontsov
файл текстовый такого содержания
Код (Text):
‘325311’,’9211001G60′,’3′,’558′,’9211001G60′,»,’1′,’1′ ‘325311’,’9211001G61′,’3′,’558′,’9211001G61′,»,’2′,’1′ ‘325311’,’946319′,’4′,’10191′,’94-6319′,»,’1′,’1′ ‘325311’,’DN5184′,’4′,’742′,’DN5184′,»,’1′,’1′ ‘325311’,’TSP0225346′,’4′,’89’,’TSP0225346′,»,’1′,’1′данные получаю в массив и загружаю в бд
runcore
читайте построчно. вставлять в БД можно сразу, можно порциями, а можно писать готовые запросы в файл и получившийся «дамп» скармливать в БД с пом mysqldump. если юзаете мускул
graf_vorontsov
та и так циклом же прохожу файл… может его както программно можно разделить выполнение файла на части, например после 20 мб выгрузить файл из памяти и продолжить с того момента на котором остановился…
не знаю.. придумал чтото нереальное
artoodetoo
Код (PHP):
// полезная работа }Добавлено спустя 1 минуту 29 секунд:
в цикле читать и писать по одной записи. а не «прочитать все и затем циклом по массиву».
runcore
да даже простого fgets($fh) хватит
artoodetoo
нет
то есть да, наверное. но та функция вроде быстрее в 100500 раз ))) судя по коментариям в офф. доке
runcore
?
artoodetoo
… и, главное, stream_get_line обрезает символ конца строки, а при fgets тебе самому надо об этом позаботиться.
graf_vorontsov
вот так считываю файл в массив
Код (Text):
function get_array($read_file){ while(($arr = fgetcsv($read_file, 100000000,»,»,»‘»))!== FALSE){ $massiv[] = array_merge($arr); } return $massiv; }ну а потом foreach…. и в бд полученые результаты
artoodetoo
Дык! У тебя почти всё готово. Совмести свои while и foreach в один цикл и выкини $massiv за ненадобностью.
graf_vorontsov
ну.. совместил…ничего не поменялось. маленький файл работает без проблем а большой пишет как и тогда
Код (Text):
$file = fopen(«cross.txt», «r»); while(($fle = fgetcsv($file, 100000000,»,»,»‘»))!== FALSE){ foreach ($fle as $nums){ } $query = mysql_query(«INSERT INTO crossnumbers (ARL_ART_ID, ARL_SEARCH_NUMBER, ARL_BRA_ID, ARL_DISPLAY_NR) VALUES (‘$fle[0]’, ‘$fle[1]’, ‘$fle[3]’, ‘$fle[4]’)»); }
artoodetoo
Блин, ну ты чо! Один цикл нужен, а не вложенные циклы.
Насколько я понимаю, надо вот так:Код (PHP):
$query = mysql_query(«INSERT INTO crossnumbers (ARL_ART_ID, ARL_SEARCH_NUMBER, ARL_BRA_ID, ARL_DISPLAY_NR) VALUES (‘$fle[0]‘, ‘$fle[1]‘, ‘$fle[3]‘, ‘$fle[4]‘)»); }Добавлено спустя 6 минут 15 секунд:
Кстати, я сейчас некоторые замеры провел. fgets просто чемпион по тормознутости! ))) Причем скорость зависит от длины строки, похоже он посимвольно читает без нормального буфера!fgetcsv работает в разы быстрее, хотя делает ещё дополнительную работу по распарсиванию строки.
stream_get_line просто метеор! Но если добавить «ручное» распарсивание считанной строки, то общий результат конечно хуже чем fgetcsv. Вполне предсказуемо.
r3l0c
stream_get_contents+str_getcsv
Добавлено спустя 38 секунд:
ой, stream_get_lineВообще кста все функции stream_ оч быстры)
Your
Памяти не хватает…
Апач не режит ничего? по Rlimit ?
Там зацепок уйма может возникнуть…
graf_vorontsov
работает быстро, читает построчно, но распарсить строку както не въеду как…
Код (Text):
while (!feof($handle)) { $line = stream_get_line($handle, 0); $fle = str_replace(«/’/», «», explode(«,», $line)); $query = mysql_query(«INSERT INTO crossnumbers (ARL_ART_ID, ARL_SEARCH_NUMBER, ARL_BRA_ID, ARL_DISPLAY_NR) VALUES (‘$fle[0]’, ‘$fle[1]’, ‘$fle[3]’, ‘$fle[4]’)»); }тут убрал вложеный массив но ошибка не исчезла
Код (Text):
while(($fle = fgetcsv($file, 100000000,»,»,»‘»))!== FALSE){ $query = mysql_query(«INSERT INTO crossnumbers (ARL_ART_ID, ARL_SEARCH_NUMBER, ARL_BRA_ID, ARL_DISPLAY_NR) VALUES (‘$fle[0]’, ‘$fle[1]’, ‘$fle[3]’, ‘$fle[4]’)»); }
graf_vorontsov
так надеюсь будет работать… завтра попробую и отпишусь, файл на работе лежит
прийдётся PHP 5.3 на работе тоже поставить.. а то str_getcsv 5,2 не хаваетКод (Text):
while (!feof($handle)) { $line = stream_get_line($handle, 0, «rn»); $fle = str_getcsv($line, «,», «»», «rn»); }
runcore
хе хе
там в комментах просто ктото неумеет пользоваться правильно этими функциями.
фишка в том, что для fgets параметр $length является необязательным. если его не указывать то:
мне самому интересно стало.
неполенился сгенерил файл на 70000 строк ~ 7 Мбайт
затестил такой код. комментил внутри цикла сначала одну, потом другую функциюКод (PHP):fgets() быстрее читает раза в 2! даже вместе с trim(), а без неё раза в 3.
с stream_get_line() такой финт неполучится, ибо у нее параметр $length ОБЯЗАТЕЛЬНЫЙ. а если строки разной длинны читаем — то приходится указывать с запасом. вот она и начинает тормозить. максимум можно уменьшить его, но уже опасность что читать будем непострочно а хз как. но если известно сколько байт читать то будет паритет, ибо $length есть у ОБОИХ функций в параметрах.
в общем. я верю только официальной доке:
тоесть они аналогичны по скорости, НО у каждой есть свои особенности. в общем случае, при чтении текстового файла с разнородными строками(как у ТС), fgets() предпочтительнее, так как сама найдет перевод строки и быстрее. зато stream_get_line() более гибкая в настройке.

