Этот вопрос перепечатан из переполнения стека на основе предложения в комментариях, извинения за дублирование.
Вопросов
Вопрос 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, сначала я загрузил двоичные файлы, содержащие строки 100 КБ, 1 М, 20 М, 200 М, используя вызов ниже.
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
Я уничтожил загрузку двоичного файла 200M (~ 3GB CSV-файл) через 2 часа.
Поэтому я запустил скрипт для создания таблицы, вставил в двоичный файл различное количество строк, а затем удалил таблицу, см. График ниже.
Вставка 1М строк из двоичного файла заняла около 7 секунд. Затем я решил протестировать вставку 1M строк за раз, чтобы увидеть, не будет ли узкого места при конкретном размере базы данных. Когда база данных достигает примерно 59 миллионов строк, среднее время вставки падает примерно до 5000 в секунду.
Установка глобального key_buffer_size = 4294967296 немного улучшила скорость вставки небольших двоичных файлов. На приведенном ниже графике показаны скорости для различного количества рядов.
Однако для вставки 1М строк это не улучшило производительность.
строк: 1 000 000 время: 0: 04: 13,761428 вставок / сек: 3940
против пустой базы данных
строки: 1 000 000 время: 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
Решение: предварительный расчет идентификатора вне MySQL вместо автоматического увеличения
Строим стол с
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';"
Получение сценария для предварительного вычисления индексов, по-видимому, устранило снижение производительности при увеличении размера базы данных.
Обновление 2 - использование таблиц памяти
Примерно в 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 минут для загрузки 100M строк, что примерно равнозначно прямой вставке в таблицу на диске.
id
должно быть быстрее. (Хотя я думаю, что вы этого не ищете)Ответы:
Хороший вопрос - хорошо объяснил.
У вас уже есть высокий (ish) параметр для буфера ключей - но достаточно ли этого? Я предполагаю, что это 64-битная установка (если нет, то первое, что вам нужно сделать, это обновление), а не запуск на MSNT. Посмотрите на вывод mysqltuner.pl после выполнения нескольких тестов.
Чтобы наилучшим образом использовать кэш, вы можете найти преимущества в пакетной / предварительной сортировке входных данных (самые последние версии команды 'sort' имеют много функций для сортировки больших наборов данных). Также, если вы генерируете идентификационные номера вне MySQL, то это может быть более эффективным.
Предполагая (опять же), что вы хотите, чтобы выходной набор вел себя как отдельная таблица, единственные преимущества, которые вы получите, - это распределение работы по сортировке и генерации идентификаторов, для которых вам не нужно больше баз данных. OTOH, используя кластер базы данных, вы получите проблемы с конкуренцией (которые вы не должны видеть, кроме как проблемы с производительностью).
Если вы можете обрабатывать данные и обрабатывать полученные наборы данных независимо, то да, вы получите выигрыш в производительности, но это не отменяет необходимость настройки каждого узла.
Проверьте, что у вас есть по крайней мере 4 Гб для sort_buffer_size.
Кроме того, ограничивающий фактор производительности зависит от дискового ввода-вывода. Существует множество способов решения этой проблемы, но вам, вероятно, следует подумать о зеркальном наборе чередующихся наборов данных на твердотельных накопителях для оптимальной производительности.
источник
load data...
это быстрее, чем вставить, так что используйте это.Если вы хотите быть действительно элегантным, вы можете создать многопоточную программу для подачи одного файла в коллекцию именованных каналов и управления экземплярами вставки.
Итак, вы настраиваете MySQL не так сильно, как свою рабочую нагрузку на MySQL.
источник
Я не помню точно syntacx, но если это не inb db, вы можете отключить проверку внешнего ключа.
Также вы можете создать индекс после импорта, это может значительно повысить производительность.
источник