LOAD DATA LOCAL INFILE - заливка файлов в MySQL

BAZAg

Client
Регистрация
08.11.2015
Сообщения
2 353
Реакции
2 766
Баллы
113
Пол дня трепало мой мозг...
Но, все же получилось!

Собственно в чём сама проблема?
Данные в MySQL можно заливать с файла используя LOAD DATA LOCAL INFILE.
Тоесть, готовим файл:
Код:
Развернуть Свернуть Копировать
"7b7a53e239400a13bd6be6c91c4f6c4e","2020","0","0","123456"
"3a824154b16ed7dab899bf000b80eeee","2022","0","0","123456"
"051928341be67dcba03f0e04104d9047","2048","0","0","123456"
Сохраняем его в условный temp.csv
C#:
Развернуть Свернуть Копировать
string path = Path.Combine(project.Directory, "temp.csv");
var dic1 = new System.Collections.Specialized.OrderedDictionary{{ "file", path}}; // используя параметр не нужно будет делать path.Replace("\\", "/");
Готовим запрос:
SQL:
Развернуть Свернуть Копировать
LOAD DATA LOCAL INFILE @file
 INTO TABLE `names_buffer`
 FIELDS TERMINATED BY ','
 ENCLOSED BY '""'
 LINES TERMINATED BY '\r\n'
 (`hash`, `domain`, `state`, `status`, `ts`);

C#:
Развернуть Свернуть Копировать
string text_out = ZennoPoster.Db.ExecuteQuery(sql, dic1 , ZennoLab.InterfacesLibrary.Enums.Db.DbProvider.MySqlClient, connect_db, "^^^", "|||").Trim();

И за задумкой все должно работать.
Но нет, так не работает...

Сначала ругается что-то там типа доступ запрещен.
AI рассказывает что нужно дать права FILE
GRANT FILE ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;
Выдал их, но, потом все же пришлось выдавать права супер пользователя:
GRANT SUPER ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;

Потом должно показать здесь ON: SHOW GLOBAL VARIABLES LIKE 'local_infile';
Установка примерно так: SET GLOBAL local_infile = 1;

И вот, права есть, настройка включена, а файл не грузится.
Оказалось, в строке подключения нужно указать параметр:
AllowLoadLocalInfile=true

Думал, что уже всё - поедет.
Нет, не едет...
Оказывается, что для того, чтобы можно было отправлять большие файлы - ещё окно увеличить нужно:
SET GLOBAL max_allowed_packet = 1073741824;
Увеличил (так вот его без супер пользовтеля увеличить не получается - из-за чего и пришлось супер пользователя давать).

Думал уже заработает. Нет, не заработало. Точнее заработало - половину файла грузит и падает по ошибке.
Оказалось, что нужно еще в строке подключения указать сколько времени ждать ответа от базы.
DefaultCommandTimeout=300 (поставил 5 минут)

И уже тогда поехало как нужно - 1 млн строчек залетает за 1 минуту примерно.
Строка подключения такая получилась:

C#:
Развернуть Свернуть Копировать
var dic = new Dictionary<string,string>();
dic["server"] = "8.8.8.8";
dic["user id"] = "username";
dic["password"] = "pass";
dic["database"] = "dbname";
dic["persistsecurityinfo"] = "True";

dic["allowuservariables"] = "True"; // пользовательские переменные начинающиеся с @
dic["pooling"] = "false"; // не держать соединение
dic["AllowLoadLocalInfile"] = "true"; // Разрешает LOAD DATA LOCAL INFILE
dic["DefaultCommandTimeout"] = "300"; // Время ожидания (в секундах) выполнения любого SQL-запроса.
string connect_db = string.Join(";",dic.Select(x=>string.Join("=", new[]{x.Key,x.Value})));

Подготовка файла:
C#:
Развернуть Свернуть Копировать
string path = Path.Combine(project.Directory, "temp.csv");
var csvLines = subChunk.AsParallel().Select(x => {
    string hash = x.GetMD5Hash();
    string ts = "123456";
    return $"\"{hash}\",\"{x}\",\"0\",\"0\",\"{ts}\"";
});
File.WriteAllLines(path, csvLines);
Сам запрос:
C#:
Развернуть Свернуть Копировать
string sql = @"
                    SET GLOBAL max_allowed_packet = 1073741824;

                    CREATE TABLE IF NOT EXISTS `names_buffer` (
                        `hash` VARCHAR(32) NOT NULL PRIMARY KEY,
                        `domain` VARCHAR(255) NOT NULL,
                        `state` INT DEFAULT 0,
                        `status` INT DEFAULT 0,
                        `ts` INT DEFAULT 0
                    ) ENGINE=InnoDB;
                    TRUNCATE TABLE `names_buffer`;
                    LOAD DATA LOCAL INFILE @file
                    INTO TABLE `names_buffer`
                    FIELDS TERMINATED BY ','
                    ENCLOSED BY '""'
                    LINES TERMINATED BY '\r\n'
                    (`hash`, `domain`, `state`, `status`, `ts`);
                    INSERT INTO `names` (`hash`, `domain`, `state`, `status`, `ts`)
                    SELECT b.`hash`, b.`domain`, b.`state`, b.`status`, b.`ts`
                    FROM `names_buffer` b
                    LEFT JOIN `names` target ON b.`hash` = target.`hash`
                    WHERE target.`hash` IS NULL;
                    TRUNCATE TABLE `names_buffer`;
                    SET GLOBAL max_allowed_packet = 4194304;
                    ";

C#:
Развернуть Свернуть Копировать
return ZennoPoster.Db.ExecuteQuery(sql, dic1 , ZennoLab.InterfacesLibrary.Enums.Db.DbProvider.MySqlClient, connect_db, "^^^", "|||").Trim();

А люди говорят вот, AI все проблемы решает...
Так вот не особо решает - то одну ересь пишет, то другую, то третью - а время то тикает...

Сюда выложил - может AI обучится и лучше будет рекомендовать ответы :)
 
  • Оценить
Реакции: borroza

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)