Импорт данных и производительность

151
07 мая 2019, 16:30

Появилась такая задачка: импорт в БД данных из CSV-файла. CSV представляет собой ненормализованную табличку, он прилетает из другого приложения и на его формат я повлиять никак не могу. БД нормальзована, поэтому вариант с LOAD DATA INFILE, наверное, не подойдет.

Условно, БД выглядит так:

CREATE TABLE `clients` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`email` VARCHAR(30) NULL DEFAULT NULL,
PRIMARY KEY (`id`), 
UNIQUE `index_clients_names` (`name`)
) ENGINE = InnoDB;
CREATE TABLE `products` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`price` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), 
UNIQUE `index_products_names` (`name`)
) ENGINE = InnoDB;
CREATE TABLE `orders` (
`id` INT NOT NULL AUTO_INCREMENT,
`client` INT NOT NULL,
`product` INT NOT NULL,
`date_time` DATETIME NOT NULL,
PRIMARY KEY (`id`), 
UNIQUE `index_order_datetime` (`date_time`)
) ENGINE = InnoDB;

CSV-файл:

John Ridger;Paper;30;2018/10/7 5:23:54 AM
Василий Кормушкин;Notebook;8;2018/10/7 8:44:28 AM
Alice McCollin;Glue;5;2018/10/7 11:9:14 AM
...

Сначала мне нужно добавить недостающие поля (если таковых ранее не было в БД) в таблички clients и products, потом уже вносить данные в orders.

Соответственно, возник вопрос - как это сделать оптимально (и с т.з. производительности/нагрузки на СУБД, и с т.з. удобства кода (используется РНР7)).

В голову приходят такие варианты:

  1. На РНР распарсить CSV в массив, затем пройтись по нему построчно с кучей INSERT'ов (вида INSERT IGNORE INTO) с клиентами и продуктами (либо с несколькими многострочными INSERT'ами). Затем еще раз пройти по массиву, SELECT'ами получить id клиентов/товаров и делать INSERT в orders. (Мне кажется, вариант дурацкий).
  2. Сделать в MySQL хранимую процедуру, принимающую имя клиента, названием товара, кол-во и дату, которая будет проверять наличие нужных значений в clients/products (и получать их id), при необходимости добавлять их туда, и в конце заносить данные в orders. (Вроде бы вариант получше, не знаю только, нет ли в MySQL каких-то ограничений, которые могут не дать это сделать. Минус в том, что вызов процедуры придется делать для каждой строчки в CSV).
  3. Сделать VIEW из этих 3х табличек через INNER JOIN, повесить на него триггер BEFORE INSERT и в нем выполнить необходимую подготовку данных - получение id, добавление недостающих данных в clients/products. Соответственно, из РНР просто делать INSERT в этот VIEW. Может быть даже LOAD DATA INFILE. (Если я правильно понял документацию по MySQL, то это невозможно из-за ограничений триггеров на кол-во изменяемых таблиц.)
  4. Сделать хранимую процедуру, которая будет создавать временную табличку, читать в нее CSV через LOAD DATA INFILE и затем уже производить манипуляции с этой таблицей, в конце смержить ее с orders. (Вообще не уверен, что MySQL позволит такое. Если все же такое возможно, то не знаю, как скажется на производительности/потреблении ресурсов создание/удаление временной таблицы при каждом импорте данных)

Больше ничего в голову не приходит, посему хотелось бы узнать мнение более опытных в этом деле людей.

READ ALSO
PDO ошибка выборки c LIMIT

PDO ошибка выборки c LIMIT

Почему выдает ошибку при таком запросе?

133
Как передать переменную через роут в посредник Laravel?

Как передать переменную через роут в посредник Laravel?

Есть роут вывода товаров с переменной $id категории, которую надо передать через посредник в контроллер и вывести товарыПосредник проверяет...

142
Заполнение данных в html из php по id

Заполнение данных в html из php по id

Ребята, помогите, пожалуйстаЕсть html с таблицей

133
Не работает условие php mysql pdo

Не работает условие php mysql pdo

Подскажите пожалуйста, почему не работает данное условие?

134