Быстрый способ заполнить реляционную базу данных в MySQL с помощью JDBC? - PullRequest
2 голосов
/ 03 мая 2011

Я пытаюсь реализовать простую программу на Java, которая будет использоваться для заполнения базы данных MySQL из исходного файла CSV.Для каждой строки в CSV-файле мне нужно выполнить следующую последовательность операторов SQL (пример в псевдокоде):

execute("INSERT INTO table_1 VALUES(?, ?)");
String id = execute("SELECT LAST_INSERT_ID()");
execute("INSERT INTO table_2 VALUES(?, ?)");
String id2 = execute("SELECT LAST_INSERT_ID()");
execute("INSERT INTO table_3 values("some value", id1, id2)");
execute("INSERT INTO table_3 values("some value2", id1, id2)");
...

Существует три основных проблемы:1. База данных не находится на локальном хосте, поэтому каждый INSERT / SELECT имеет задержку, и это основная проблема2. CSV-файл содержит миллионы строк (например, 15 000 000), поэтому это занимает слишком много времени.3. Я не могу изменить структуру базы данных (добавить дополнительные таблицы, отключить ключи и т. Д.).

Мне было интересно, как я могу ускорить процесс INSERT / SELECT?В настоящее время 80% времени выполнения расходуется на связь.

Я уже пытался сгруппировать вышеупомянутые операторы и выполнить их как пакетные, но из-за LAST_INSERT_ID это не работает.В любых других случаях это занимает слишком много времени (см. Пункт 1).

Ответы [ 2 ]

3 голосов
/ 04 мая 2011

Самый быстрый способ - разрешить MySQL анализировать CSV и загружать записи в таблицу. Для этого вы можете использовать «LOAD DATA INFILE»:

http://dev.mysql.com/doc/refman/5.1/en/load-data.html

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

Как только это будет сделано, у вас может появиться столбец, который указывает, были ли обработаны записи или нет. По умолчанию его значение должно быть ложным.

Как только данные загружены, вы можете забрать все записи, где обработано = false.

Для всех таких записей вы можете заполнить таблицы 2 и 3.

Поскольку все эти операции будут выполняться на сервере, задержка клиента сервера <> не будет учитываться.

1 голос
/ 03 мая 2011

Подача данных в черную дыру

CREATE TABLE  `test`.`blackhole` (
  `t1_f1` int(10) unsigned NOT NULL,
  `t1_f2` int(10) unsigned NOT NULL,
  `t2_f1` ... and so on for all the tables and all the fields.
) ENGINE=BLACKHOLE DEFAULT CHARSET=latin1;

Обратите внимание, что это таблица blackhole, поэтому данные идут в никуда.
Однако вы можете создать триггерна столе черной дыры, что-то вроде этого.

И передать его с помощью триггера

delimiter $$

create trigger ai_blackhole_each after insert on blackhole for each row
begin
  declare lastid_t1 integer;
  declare lastid_t2 integer;

  insert into table1 values(new.t1_f1, new.t1_f2);
  select last_insert_id() into lastid_t1;
  insert into table2 values(new.t2_f1, new.t2_f1, lastid_t1);
  etc....
end$$

delimiter ;

Теперь вы можете заполнять таблицу blackhole одним оператором вставки на полной скорости и даже вставлять несколько строк в одинgo.

insert into blackhole values(a,b,c,d,e,f,g,h),(....),(...)...

Отключение обновлений индекса для ускорения работы

ALTER TABLE $tbl_name DISABLE KEYS;
....Lot of inserts
ALTER TABLE $tbl_name ENABLE KEYS;

Отключение всех неуникальных обновлений ключей и ускорениевставка. (ключ автоинкремента уникален, поэтому на него это не влияет)

Если у вас есть какие-либо уникальные ключи, и вы не хотите, чтобы MySQL проверял их во время массовой вставки, убедитесь, что вывыполните alter table, чтобы исключить уникальный ключ и включить его впоследствии.
Обратите внимание, что alter table для возврата уникального ключа займет long time.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...