Как сделать тяжелый импорт из excel 800к товаров?

Добрый вечер, возникла задача сделать выгрузку.

Мы имеем:
1. Фото
2. excel файл с 800к товарами
3. пустую sql таблицу

Все хорошо, все просто:
1. подключаем любую либу для работы php с excel
2. парсим информацию из документа
3. загружаем фото (имя файла = артикул )
4. заполняем таблицу sql.

Но возможно я недооцениваю скорость и возможности самых обычных хостингов (Характеристик железок не знаю, но возьмем самый классический рублей за 200, 2 гб памяти, hdd)
, но у меня по ощущениям, при попытке сделать все это, сервер сложиться и откажется проделывать это все 800.000 раз, так ли это, и как найти выход из этого?

Как вариант разбить весь процесс на части, по 50к товаров за 1 раз, но тут вопрос, как это реализовать?
У меня в голове только 1 вариант:
Брать срез в 50к записей со смещением, а смещение узнавать по GET параметру, например:

site.ru/import?step=2 (значит берем срез ( начиная с 50к товара и заканчивая 100к товаром)

Но я думаю что делаю какую-то колхозную чепуху своими срезами с get параметром, можно же как-то это сделать нормально?

Подскажите будьте добры
  • Вопрос задан
  • 5209 просмотров
Решения вопроса 1
syschel
@syschel
freelance/python/django/backend
1. У вас именно EXEL файл или всётаки CSV который вы открываете на десктопе с помощью экселя?
2. Если всётаки EXEL файл. Там слишком много всего нагорожено, на вроде вёрсток и формул или голые таблицы?
3. Если всётаки голые таблицы. Вы можете делать именно CSV файл?

Если данные будут в CVS формате, то можно всё загрузить средствами MYSQL и не использовать для обработки PHP или его библиотеки. Тогда результат будет в разы выше, чем если перебирать с помощью ПХП и потом кормить в MSQL

Когда я в своё время сталкивался с проблемой загрузки файла товаров в базу, там было несколько миллионов единиц, то оптимальным стало именно такое решение > LOAD DATA

Кусок моего старого MySQL кода, для наглядности
// Загружаем кашерный файл
LOAD DATA LOCAL INFILE '/srv/cms_cpa/files/adimport_items.csv' INTO TABLE adimport_tmp CHARACTER SET utf8 FIELDS TERMINATED BY '|' ENCLOSED BY "'" LINES TERMINATED BY '\n' IGNORE 1 LINES (id_adimport,article,available,currencyId,delivery,description,id,name,oldprice,param,picture,price,url,vendor,advcampaign_id,advcampaign_name);

// Загружаем только нужные поля (!!!)
LOAD DATA LOCAL INFILE '/srv/cms_cpa/files/adimport_items.csv' INTO TABLE adimport_tmp CHARACTER SET utf8 FIELDS TERMINATED BY '|' ENCLOSED BY "'" LINES TERMINATED BY '\n' IGNORE 1 LINES (id_adimport,@ISBN,@adult,@age,article,@attrs,@author,available,@barcode,@binding,@brand,@categoryId,@country_of_origin,currencyId,delivery,description,@downloadable,@format,@gender,id,@local_delivery_cost,@manufacturer_warranty,@market_category,@model,@modified_time,name,oldprice,@orderingTime,@page_extent,param,@performed_by,@pickup,picture,price,@publisher,@sales_notes,@series,@store,@syns,@topseller,@type,@typePrefix,url,vendor,@vendorCode,@weight,@year,advcampaign_id,advcampaign_name,@deeplink);

// Все поля
LOAD DATA LOCAL INFILE '/srv/cms_cpa/files/adimport_items.csv' INTO TABLE adimport_tmp CHARACTER SET utf8 FIELDS TERMINATED BY '|' ENCLOSED BY "'" LINES TERMINATED BY '\n' IGNORE 1 LINES (id_adimport,ISBN,adult,age,article,attrs,author,available,barcode,binding,brand,categoryId,country_of_origin,currencyId,delivery,description,downloadable,format,gender,id,local_delivery_cost,manufacturer_warranty,market_category,model,modified_time,name,oldprice,orderingTime,page_extent,param,performed_by,pickup,picture,price,publisher,sales_notes,series,store,syns,topseller,type,typePrefix,url,vendor,vendorCode,weight,year,advcampaign_id,advcampaign_name,deeplink);

Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 16
webinar
@webinar Куратор тега PHP
Учим yii: https://youtu.be/-WRMlGHLgRg
1. xls - это похититель ресурсов, пересохраняем в csv
2. проверяем файл на размер и на лимиты при отправке через post
3. вероятно стоит его разбить на части, а не обрабатывать весь
4. наверное стоит повесить задачи по обработке на cron
5. можно и даже нужно установить больший timeout

Если для этой задачи есть web интерфейс, я бы разбивки вообще возложил на клиент. Отправлял маленькими частями ajax-ом, получал бы ответ, рисовал бы % выполнения и отправлял дальше.
Ответ написан
MaxDukov
@MaxDukov
впишусь в проект как SRE/DevOps.
xls сохранить в csv, дальше LOAD DATA INFILE в mysql-ной консоли. Загружал таким образом файлики на десятки миллионов строк - залетает на ура.
Ответ написан
Комментировать
@mykolaim
PHP developer
Импортировал 1,5 ляма строк в бд - все довольно быстро.
1 - консольное приложение, зачем вам мучать сервер.
2 - для чтения советую https://github.com/box/spout
3 - выгрузить фото архивом на хост, там распаковать ну и в скрипте только путь правильный подставить.

И не нужно никакой магии.
Ответ написан
Комментировать
Способы:
1. Посмотрите есть ли ограничения на POST запросы на вашем сервер (по моему вы легко в них вложитесь) и просто одним запросом все вставьте как написал Дмитрий Богданов используя BATCH INSERT.
2. Составьте SQL запрос с импортируемыми данными запишите его в файл. Скопируйте через scp на сервер и выполните.
Ответ написан
Комментировать
solotony
@solotony
покоряю пик Балмера
оптимально по быстродействию - LOAD DATA INFILE. но "минус" - валидацию не выполнить, и обновление тоже

если нужна валидация - надо парсить самостоятельно. Для ускорения SQL делайте вставки пакетами
insert ignore ..... values (),(),() ...

если нужно обновление
insert ignore ..... values (),(),() ... on duplicate key update

если скрипт обрубается лимитами - создавайте задание, и обрабатывайте по крон

800К это не много.
Ответ написан
Комментировать
@AlexSer
ставь DBFORGE сделай загрузку с данных XLS, и пиши запросы в таблицу.
Ответ написан
Комментировать
php10
@php10
Разработчик на PHP
делайте BATCH INSERT через PHP CLI
Ответ написан
Комментировать
zualex
@zualex
Senior Software Engineer
Мне кажется что лучше один большой файл разбить на несколько файлов и не париться
Ответ написан
danial72
@danial72
flutter dart.
Перевести xls в csv и использовать pipe подход. Построчно считывать файл, не загружая в память полностью.

https://m.habr.com/post/345024/
Тут отлично описано что вам нужно
Ответ написан
Комментировать
pingo
@pingo
>>подключаем любую либу
вот тут вопрос как раз.. у меня было такое, что только не пробовал, от unset в каждой итерации до всяких других бубнов, пока либу не поменял.
строк было ~400к по 16 полей, что на что поменял, не помню, просто делал composer require new\officelib и правил класс, но на второй или третьей все быстро сделалось
Ответ написан
Комментировать
Taraflex
@Taraflex
Ищу работу. Контакты в профиле.
https://github.com/box/spout умеет в поточное чтение и запись.
В базе выключите индексацию перед вставкой. Вставку делайте пачками а не по одной записи.
Ответ написан
Комментировать
Expany
@Expany
$this->get('skill');
Че пасаны, цикл на № итераций, с паузой, не?
К примеру на 100 итераций и паузу в 1с, не?
Ответ написан
iCoderXXI
@iCoderXXI
React.JS/FrontEnd engineer
Сконвертировать XLS посредством скрипта в SQL пакетами по 50к строк и пулять в базу из консоли.
Ответ написан
Комментировать
@ivanovnickolay
https://github.com/box/spout отличное решение для чтения файлов экселя формата xlxs. Сам его использую для загрузки данных с предварительной валидацией. Реально более 12 мб памяти не используется. По сравнению с phpExcell достаточно быстрое решение.
Ответ написан
Комментировать
alex-1917
@alex-1917
Если ответ помог, отметь решением
Все хорошо, все просто:
1. подключаем любую либу для работы php с excel
2. парсим информацию из документа
3. загружаем фото (имя файла = артикул )
4. заполняем таблицу sql.

)))))

1. Устанавливаем www.mysqlfront.de
2. Скармливаем ваш ексель-пексель
3. Начинаем продавать ваши 800к товаров

p.s. насчет фото информации мало, поэтому то вы уж сами как-нибудь)))
почему мало? ну хотя бы потому, что 800к фото в одну папку совать - тупиковый путь. надо хотя бы по 1-3к в папку. Найдите любой менеджер файлов и раскидайте по папкам, самое простое - первые три символа из имени файла будут названием папки. Тут опять же возможны коллизии, так как будут повторы.. а может и не будут...
Хотя у вас уже полдела сделано (имя фото = артикул).
Эту расфасовку обязательно сделать перед заливкой, затем в архив и заливать через фтп, на хостинге файл распаковать.. Хотя 800к*50кб = 40Гб и это если по одному фото на товар! Вы там про какие 2Гб говорили?)))
Ответ написан
Комментировать
Сохранить в формате xlsx, переименовать в zip и разархивировать. Там найти xml и делать с ним что угодно
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы