Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Импорт и обработка большого файла CSV
Форумы портала PHP.SU » » Вопросы новичков » Импорт и обработка большого файла CSV

Страниц (1): [1]
 

1. dmaw - 24 Июля, 2016 - 18:53:39 - перейти к сообщению
Добрый день!

Есть Интернет-магазин и поставщик с CSV-прайсом на 20 000 строк/товаров.
Мне нужно чтобы скрипт с помощью крона ежедневно обновлял цены из CSV.
Делаю я это так: скачиваю новый CSV, читаю файл построчно, ищу совпадения по артикулу, если товар есть обновляю его цену и наличие, если товар не найден, то создаю его.
Проблема в том, что скрипт перестаёт работать после 10 000 строк.

Вопрос: можно ли как-то давать скрипту "передышку" или как-то разбивать процесс на мелкие, чтобы скрипт успевал обработать все 20 000 строк?

Часть кода:
PHP:
скопировать код в буфер обмена
  1. //читаю весь файл в массив
  2. $arr = array();
  3. $file = fopen('price.csv', 'r');
  4. while(!feof($file))
  5. {
  6.      $arr[] = fgetcsv($file, 0, ";");
  7. }
  8. fclose($file);
  9.  
  10. foreach($arr as $row) // Цикл по строкам
  11. {
  12. // тут начинаются проверки на существование товаров и обновление цен.
  13.  
2. Мелкий - 24 Июля, 2016 - 19:53:51 - перейти к сообщению
create temporary table
load data infile
create index on temporary table, если нужно для мерджа
begin
multitable update, insert .. select, delete если нужен
commit
drop temporary table
Чистый sql, всосать и помержить можно огромный массив данных.
3. Fart - 25 Июля, 2016 - 06:50:43 - перейти к сообщению
ты даже поленился зайти по ссылке csv на сайте. проверяешь конец файла зачем? тебе первоначально нужно прогнать по-бырому счетчик, а ты феофиш как старушка с клюшкой на лестничной площадке!!! попробуй примеры сначала использовать. как код оптимизируешь звони !!!

у базы данных записей может быть и миллион, а с корявым кодом и БД даст такой отклик, что проще не заниматься программированием вовсе!!!!
4. dmaw - 25 Июля, 2016 - 12:55:57 - перейти к сообщению
Fart пишет:
ты даже поленился зайти по ссылке csv на сайте. проверяешь конец файла зачем? тебе первоначально нужно прогнать по-бырому счетчик, а ты феофиш как старушка с клюшкой на лестничной площадке!!!

Проверил оба варианта на скорость выполнения:
PHP:
скопировать код в буфер обмена
  1. while(!feof($file)) // 2.3 сек
  2. while(($data = fgetcsv($file, 0, ";")) !== FALSE) // 2.5 ... 3 сек

Старушка оказалась ни при чём Улыбка
5. Fart - 27 Июля, 2016 - 18:41:54 - перейти к сообщению
1. проверить память
2. отказаться от работы с fgetcsv и ИМХО ручками обрабатывать файл. с fgets работает в х10-х20 раз быстрее
3. проверить сам файл, возможны ошибки и цсв сам по себе очень баговый формат.

PS да и вообще, приятнее работать с json
6. dmaw - 27 Июля, 2016 - 19:11:39 - перейти к сообщению
Fart пишет:
1. проверить память
2. отказаться от работы с fgetcsv и ИМХО ручками обрабатывать файл. с fgets работает в х10-х20 раз быстрее
3. проверить сам файл, возможны ошибки и цсв сам по себе очень баговый формат.

PS да и вообще, приятнее работать с json

fgets проверил на скорость, раза в два быстрее данные получает, этого всё равно будет мало.
ЦСВ без ошибок, просто очень большой Улыбка
json я бы и сам рад, но поставщикам не прикажешь, есть такие кто екселем отдаёт Улыбка
Fart, спасибо!
(Добавление)
Суть даже не в скорости чтения через fgetcsv, там 2-3 секунды, а в том, что я в цикле потом запросы делаю, т.е. фактически получается сколько строк столько и запросов, поэтому получается фигня. Самый правильный ответ дал Мелкий, только надо догнать как всё это построить.
7. Fart - 27 Июля, 2016 - 21:29:02 - перейти к сообщению
у меня за 2.0 сек обрабатывает цсв файл объемов 50-60мб.

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

по поводу скорости: лучше на php7 переходить с норм хостом... а с файлами работать начинает тяжело если объем большой и требуется более быстрого отклика.

по поводу СУБД... тут очевидно. с работой такого объема быстрее и проще...

PS либо переписать логику составления файлов цсв на мелкие с определенной категорией
8. dmaw - 27 Июля, 2016 - 22:58:25 - перейти к сообщению
Fart, спасибо, за помощь, попробую свои мысли реализовать.
По поводу php7 вопрос сложный, магазин официальный и находится в Беларуси, а у нас тут с одной стороны выбирать нет из чего, а с другой чудо законы, которые не позволяют размещать сайты за пределами страны.
9. dmaw - 30 Июля, 2016 - 23:10:06 - перейти к сообщению
Как упаковать 20 000 подобных запросов в один?

CODE (SQL):
скопировать код в буфер обмена
  1. UPDATE products SET price='8.04', WHERE artikul='456457' LIMIT 1 ;
  2. UPDATE products SET price='20.59', WHERE artikul='2346456465' LIMIT 1 ;
  3. UPDATE products SET price='2.16', WHERE artikul='345637457' LIMIT 1 ;
  4. UPDATE products SET price='6.67', WHERE artikul='34577457' LIMIT 1 ;
  5. UPDATE products SET price='165.31', WHERE artikul='75457' LIMIT 1 ;
  6. UPDATE products SET price='9.91', WHERE artikul='3463457457' LIMIT 1 ;
10. Fart - 31 Июля, 2016 - 10:48:47 - перейти к сообщению
где то уже была тема про это. Вроде бы товарищ Мелкий приводил пример. в инете есть такой вариант:

UPDATE 'some_table'
SET
'field_1' = CASE 'id'
WHEN id_1 THEN data_1
WHEN id_2 THEN data_2
...
WHEN id_N THEN data_N
ELSE 'field_1' END,
'field_2' = CASE 'id'
WHEN id_1 THEN data_1
WHEN id_2 THEN data_2
...
WHEN id_N THEN data_N
ELSE 'field_2' END,

...

'field_N' = CASE 'id'
WHEN id_1 THEN data_1
WHEN id_2 THEN data_2
...
WHEN id_N THEN data_N
ELSE 'field_N' END
11. dmaw - 31 Июля, 2016 - 14:29:26 - перейти к сообщению
Что-то не догоняю как эту конструкцию правильно составить, нашел такой вариант:
CODE (SQL):
скопировать код в буфер обмена
  1. UPDATE mytable SET
  2.     fruit = CASE WHEN id=1 THEN 'orange' ELSE 'strawberry' END,
  3.     drink = CASE WHEN id=1 THEN 'water'  ELSE 'wine'       END,
  4.     food  = CASE WHEN id=1 THEN 'pizza'  ELSE 'fish'       END
  5. WHERE id IN (1,2);

т.е. как я понимаю на каждую ячейку будет куча условий в зависимости от строки. ELSE наверное мне не нужен.

 

Powered by ExBB FM 1.0 RC1