Построение 1000-метровой таблицы MySQL

18

Этот вопрос перепечатан из переполнения стека на основе предложения в комментариях, извинения за дублирование.

Вопросов

Вопрос 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 строк, что примерно равнозначно прямой вставке в таблицу на диске.

Бен
источник
1
Я думаю, что изменение первичного ключа на просто idдолжно быть быстрее. (Хотя я думаю, что вы этого не ищете)
DavidEG
Привет, Дэвид, спасибо за комментарий, к сожалению, без ключа запросы, которые нам нужно сделать, не достаточно быстрые (логика выбора первичного ключа изложена в этом посте stackoverflow.com/questions/4282526/mysql-group-by- оптимизация )
Бен
1
Это только для тестирования? Возможно, вы захотите взглянуть на движок MySQL MEMORY: dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html Если вы планируете развернуть его как архитектуру, мне интересно, как вы планируете восстановление после сбоев, кажется, что-то, что было бы лучше обрабатывать MapReduce / Hadoop.
полином
Привет, многочлен, спасибо за подсказку, в данный момент мы просто тестируем разные детекторы функций в разных масштабах, после того как база данных сгенерирована, она не сильно изменится (в любом случае, в текущей спецификации)
Бен

Ответы:

4

Хороший вопрос - хорошо объяснил.

Как я могу настроить MySQL для увеличения скорости вызова LOAD DATA INFILE?

У вас уже есть высокий (ish) параметр для буфера ключей - но достаточно ли этого? Я предполагаю, что это 64-битная установка (если нет, то первое, что вам нужно сделать, это обновление), а не запуск на MSNT. Посмотрите на вывод mysqltuner.pl после выполнения нескольких тестов.

Чтобы наилучшим образом использовать кэш, вы можете найти преимущества в пакетной / предварительной сортировке входных данных (самые последние версии команды 'sort' имеют много функций для сортировки больших наборов данных). Также, если вы генерируете идентификационные номера вне MySQL, то это может быть более эффективным.

будет использовать кластер компьютеров для загрузки различных файлов CSV

Предполагая (опять же), что вы хотите, чтобы выходной набор вел себя как отдельная таблица, единственные преимущества, которые вы получите, - это распределение работы по сортировке и генерации идентификаторов, для которых вам не нужно больше баз данных. OTOH, используя кластер базы данных, вы получите проблемы с конкуренцией (которые вы не должны видеть, кроме как проблемы с производительностью).

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

Проверьте, что у вас есть по крайней мере 4 Гб для sort_buffer_size.

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

symcbean
источник
1
  • Рассмотрим ваш ограничивающий фактор. Это почти наверняка однопоточная обработка процессора.
  • Вы уже определили, что load data...это быстрее, чем вставить, так что используйте это.
  • Вы уже определили, что действительно большие файлы (по номеру строки) сильно замедляют работу; Вы хотите разбить их на куски.
  • Используя неперекрывающиеся первичные ключи, поставьте в очередь как минимум N * процессорных наборов, используя не более миллиона строк ... возможно, меньше (тест производительности).
  • Используйте последовательные блоки первичных ключей в каждом файле.

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

Итак, вы настраиваете MySQL не так сильно, как свою рабочую нагрузку на MySQL.

Джефф Ферланд
источник
-1

Я не помню точно syntacx, но если это не inb db, вы можете отключить проверку внешнего ключа.

Также вы можете создать индекс после импорта, это может значительно повысить производительность.

Жюльен Дюпоншель
источник
Откладывание перестроения индекса только повышает производительность, когда количество строк в таблице значительно меньше, чем количество добавляемых строк.
Symcbean