Этот вопрос отправлен с Переполнение стека на основе предложения в комментариях, приносим свои извинения за дублирование.
Вопрос 1: по мере увеличения размера таблицы базы данных, как мне настроить MySQL для увеличения скорости вызова LOAD DATA INFILE?
Вопрос 2: будет ли использование кластера компьютеров для загрузки различных CSV-файлов улучшением производительности или уничтожением? (это моя завтрашняя контрольная задача с использованием данных загрузки и массовых вставок)
Мы пробуем различные комбинации детекторов функций и параметров кластеризации для поиска изображений, поэтому нам нужно иметь возможность своевременно создавать большие базы данных.
У машины 256 гигабайт оперативной памяти, и есть еще 2 машины с таким же объемом оперативной памяти, есть ли способ сократить время создания за счет распределения базы данных?
схема таблицы выглядит как
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| match_index | int(10) unsigned | NO | PRI | NULL | |
| cluster_index | int(10) unsigned | NO | PRI | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| tfidf | float | NO | | 0 | |
+---------------+------------------+------+-----+---------+----------------+
создан с
CREATE TABLE test
(
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL AUTO_INCREMENT,
tfidf FLOAT NOT NULL DEFAULT 0,
UNIQUE KEY (id),
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
Первым шагом было сравнение массовых вставок и загрузки из двоичного файла в пустую таблицу.
It took: 0:09:12.394571 to do 4,000 inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file
Учитывая разницу в производительности, я пошел с загрузкой данных из двоичного файла csv, сначала я загрузил двоичные файлы, содержащие строки 100K, 1M, 20M, 200M, используя вызов ниже.
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
Я убил загрузку двоичного файла с 200 мегабайтами (~ 3 ГБ файла csv) через 2 часа.
Поэтому я запустил сценарий для создания таблицы и вставил разное количество строк из двоичного файла, а затем отбросил таблицу, см. График ниже.
Вставка 1M строк из двоичного файла заняла около 7 секунд. Затем я решил протестировать вставку 1 миллиона строк за раз, чтобы увидеть, не возникнет ли узкое место при конкретном размере базы данных. После того, как база данных поразила примерно 59 миллионов строк, среднее время вставки упало примерно до 5000 в секунду.
Установка глобального key_buffer_size = 4294967296 немного повысила скорость вставки небольших двоичных файлов. На приведенном ниже графике показаны скорости для разного количества строк.
Однако для вставки 1M строк это не улучшило производительность.
строк: 1000000 раз: 0: 04: 13.761428 вставок / сек: 3940
vs для пустой базы данных
строк: 1000000 раз: 0: 00: 6,339295 вставок / сек: 315,492
Выполнение загрузки данных с использованием следующей последовательности по сравнению с использованием просто команды загрузки данных
SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
Таким образом, это выглядит довольно многообещающим с точки зрения размера создаваемой базы данных, но другие параметры, похоже, не влияют на производительность вызова загрузки данных в файл.
Затем я попытался загрузить несколько файлов с разных компьютеров, но команда load data infile блокирует таблицу из-за большого размера файлов, из-за чего другие машины выходят из строя с
ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction
rows: 10,000,000 seconds rows: 0:01:36.545094 inserts/sec: 103578.541236
rows: 20,000,000 seconds rows: 0:03:14.230782 inserts/sec: 102970.29026
rows: 30,000,000 seconds rows: 0:05:07.792266 inserts/sec: 97468.3359978
rows: 40,000,000 seconds rows: 0:06:53.465898 inserts/sec: 96743.1659866
rows: 50,000,000 seconds rows: 0:08:48.721011 inserts/sec: 94567.8324859
rows: 60,000,000 seconds rows: 0:10:32.888930 inserts/sec: 94803.3646283
Создание таблицы с
CREATE TABLE test (
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL ,
tfidf FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
с SQL
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
Получение сценария для предварительного вычисления индексов, похоже, устранило снижение производительности по мере роста базы данных.
Примерно в 3 раза быстрее, без учета затрат на перемещение таблицы из оперативной памяти в таблицу на диске.
rows: 0 seconds rows: 0:00:26.661321 inserts/sec: 375075.18851
rows: 10000000 time: 0:00:32.765095 inserts/sec: 305202.83857
rows: 20000000 time: 0:00:38.937946 inserts/sec: 256818.888187
rows: 30000000 time: 0:00:35.170084 inserts/sec: 284332.559456
rows: 40000000 time: 0:00:33.371274 inserts/sec: 299658.922222
rows: 50000000 time: 0:00:39.396904 inserts/sec: 253827.051994
rows: 60000000 time: 0:00:37.719409 inserts/sec: 265115.500617
rows: 70000000 time: 0:00:32.993904 inserts/sec: 303086.291334
rows: 80000000 time: 0:00:33.818471 inserts/sec: 295696.396209
rows: 90000000 time: 0:00:33.534934 inserts/sec: 298196.501594
путем загрузки данных в таблицу на основе памяти и последующего копирования их в таблицу на диске кусками накладные расходы составляли 10 минут 59,71 секунды для копирования 107,356,741 строки с запросом
insert into test Select * from test2;
что дает примерно 15 минут для загрузки 100 миллионов строк, что примерно то же самое, что и прямая вставка их в таблицу на диске.
Хороший вопрос - хорошо объясненный.
как я могу настроить MySQL, чтобы увеличить скорость вызова LOAD DATA INFILE?
У вас уже есть высокий (ish) параметр для ключевого буфера - но достаточно ли этого? Я предполагаю, что это 64-разрядная установка (если нет, то первое, что вам нужно сделать, это обновить), а не на MSNT. Посмотрите на вывод mysqltuner.pl после выполнения нескольких тестов.
Чтобы использовать кеш наилучшим образом, вы можете найти преимущества в пакетной / предварительной сортировке входных данных (самые последние версии команды 'sort' имеют много функций для сортировки больших наборов данных). Кроме того, если вы генерируете идентификационные номера вне MySQL, это может быть более эффективным.
будет использовать кластер компьютеров для загрузки различных файлов CSV
Если предположить (опять же), что вы хотите, чтобы выходной набор вел себя как единая таблица, то единственные преимущества, которые вы получите, - это распределение работы по сортировке и генерации идентификаторов, для чего вам не нужно больше баз данных. OTOH с использованием кластера базы данных, вы получите проблемы с конкуренцией (которые вы не должны видеть кроме как проблемы с производительностью).
Если вы можете сегментировать данные и независимо обрабатывать полученные наборы данных, то да, вы получите преимущества в производительности, но это не отменяет необходимости настраивать каждый узел.
Убедитесь, что у вас есть как минимум 4 ГБ для sort_buffer_size.
Помимо этого, ограничивающим фактором производительности является дисковый ввод-вывод. Есть много способов решить эту проблему, но вам, вероятно, следует рассмотреть возможность создания зеркального набора чередующихся наборов данных на SSD для оптимальной производительности.
load data...
быстрее, чем вставка, поэтому используйте это.Если вы хотите быть по-настоящему элегантным, вы можете создать многопоточную программу для передачи одного файла в набор именованных каналов и управления экземплярами вставки.
Таким образом, вы не настраиваете MySQL для этого столько, сколько настраиваете свою рабочую нагрузку на MySQL.
Я точно не помню синтаксис, но если это innodb, вы можете отключить проверку внешнего ключа.
Также вы можете создать индекс после импорта, это может действительно повысить производительность.