Есть файл, в нем 300.000 строк, мне нужно обработать каждую строку, и добавть значение в базу. Использую стандартную функцию php
$read = fopen('file.csv', 'r');
while( ($str = fgetcsv($read, 8000, ',')) !== FALSE ):
//... парсинг файла
endwhile;
Сам файл обрабатывается очень быстро, около 0.6 - 0.9сек.
Но когда добавляю проверку строки, или значения - то скорость увеличивается минимум в 1 раз. Это понятно, что на 300к строк добавить проверку, и это занимает время.
Но потом, еще мне нужно добавить все эти строки в базу, я комбинирую запросы, и отправляю в 1ом запросе по несколько запросов комбинирую.
$sql_add = "UPDATE `table`
SET `prof` = '1,4,6,8'
WHERE `id` IN(2,3,4,1,1,2233,3321,1,3,2... сюда еще дописывается в среднем до 1000 айдишников)";
$query = Db::query($sql_add);
$query->closeCursor();# не ждать ответа от запроса
И вот благодаря таким комбинированным запросам - кол-во запросов уменьшается. Но все равно, на 100к записей приходит около 1.250запросов, и у меня скрипт виснет на долгое время, вплоть до таймаута.
Как такие большие файлы разбирают, и как их в базу быстро добавлять?.. Если основное время уходит на отправку запросов и проверку данных.
Проблема известная, и не всегда доступны для изменения параметры таймаута на сервере. Для обработки длинных запросов многие плагины (например, резервного копирования) разбивают свой код на куски (chunks), которые перезапускают сами себя для продолжения. Или создают очередь кусков, которые потом выполняются один за другим.
Я делал такое на WordPress для закачки 14 тыс товаров. Не знаю, на чем у Вас сайт, но общий принцип работы один и тот же: запуск кусков из очереди по cron.
Рекомендую сделать импорт файла напрямую в БД посредством LOAD INFILE:
Создаёте стаблицу, подходящую под файл:
CREATE TABLE 'CSVImport' (id INT);
ALTER TABLE CSVImport ADD COLUMN Title VARCHAR(256);
ALTER TABLE CSVImport ADD COLUMN Company VARCHAR(256);
ALTER TABLE CSVImport ADD COLUMN NumTickets VARCHAR(256);
Загружаете:
LOAD DATA INFILE '/home/paul/clientdata.csv' INTO TABLE CSVImport;
А потом делаете вставку в нужную вам таблицу через INSERT INTO (SELECT ... FROM CVSImport)
Могу предложить использовать подготовленные запросы.
$connection->autocommit(false); //Отключам автоматическую фиксацию изменений базы данных при проведении транзакции. И, собственно, начиинаем саму транзакцию
if (!($stmt = $connection->prepare("INSERT INTO orders (id_orders, id_handlings, id_gens, id_gens_groups, id_genotypes, id_staff, consider_cost) VALUES (DEFAULT, '$id_handlings', ?, ?, DEFAULT, DEFAULT, DEFAULT)"))) {die($connection->error);}; //Подготоавливаем запрос
if (!$stmt->bind_param('ii', $id_gens, $id_gens_groups)) {die($connection->error);}; //Привязываем переменные - обе integer => ii
$id_gens=15; //получаем значение одной из переменных
$id_gens_groups=25;
if (!$stmt->execute()) {die($connection->error);}; //Выполняем подготовленный запрос.
if (!$connection->commit()) {die($connection->error);}; //Сохраняем транзакцию
Таким образом БД не будет каждый раз компилировать каждый запрос. А скомпилирует его раз и будет просто подставлять значения. Это должно помочь.
К тому же время работы скрипта (максимальное) можно увеличить или вовсе убрать таймаут
set_time_limit(0); //Устанавливаем максимальное время выполнения скрипта в секундах. Ноль - неограничено.
Вариант ещё один. Скачать БД и поднять её на локальной машине. Провести все манипуляции на локальной машине, создать копию и заменить на сервере.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Добрый день, прошу пнуть на нужный материал или мысльТема такая, что сайт на хостинге и выполнены настройки согласно документации хоста
До версии MySQL 56+ тип таблиц MyISAM не поддерживает полнотекстовый поиск
Допустим у меня есть такая теоретическая ситуация, что мне необходимо отозвать все access token-ы конкретного пользователя, по какой-то его манипуляции