Улучшить производительность mysql LOAD DATA/mysqlimport?

Я объединяю CSV 15 ГБ (30 миллионов строк) в базу данных mysql-8.

Проблема: задача выполняется около 20 минут, с пропускной способностью примерно 15-20 МБ/с. В то время как жесткий диск способен передавать файлы со скоростью 150 МБ/с.

У меня есть RAM-диск объемом 20 ГБ, на котором хранится мой csv. Импортируйте следующим образом:

mysqlimport --user="root" --password="pass" --local --use-threads=8 mytable /tmp/mydata.csv

Это использует LOAD DATA под капотом. В моей целевой таблице нет индексов, но около 100 столбцов (я не могу это изменить).

Что странно: в /etc/mysql/my.cnf пробовал подкрутить несколько параметров конфига следующим образом, но существенного улучшения они не дали:

log_bin=OFF
skip-log-bin
innodb_buffer_pool_size=20G
tmp_table_size=20G
max_heap_table_size=20G
innodb_log_buffer_size=4M
innodb_flush_log_at_trx_commit=2
innodb_doublewrite=0
innodb_autoinc_lock_mode=2

Вопрос: учитывают ли LOAD DATA / mysqlimport эти изменения конфигурации? Или обходит? Или я вообще использовал правильный файл конфигурации?

По крайней мере, выбор переменных показывает, что они правильно загружены сервером mysql. Например, show variables like 'innodb_doublewrite' показывает OFF

В любом случае, как я могу улучшить скорость импорта? Или моя база данных является узким местом и нет возможности преодолеть порог в 15-20 МБ/с?

Обновление: интересно, если я импортирую свой csv с жесткого диска на виртуальный диск, производительность будет почти такой же (немного лучше, но никогда не выше 25 МБ/с). Я также протестировал такое же количество строк, но только с несколькими (5) столбцами. И там я получаю около 80 МБ/с. Итак, ясно, что количество столбцов является узким местом? Но почему большее количество столбцов замедляет этот процесс?


person membersound    schedule 09.10.2019    source источник
comment
Это настройки сервера, поэтому клиент не должен их соблюдать. Вы перезапускали mysql после настройки каких-либо настроек?   -  person Shadow    schedule 09.10.2019
comment
Естественно я сделал перезагрузку. Из выбора show variables like я вижу, что все мои конфиги загружены.   -  person membersound    schedule 09.10.2019
comment
100 строк? Возможно, вы имели в виду 100 столбцов?   -  person Rick James    schedule 16.10.2019
comment
Сколько у вас оперативной памяти? Насколько велик этот RAM-диск?   -  person Rick James    schedule 16.10.2019
comment
Как часто нужно выполнять нагрузку?   -  person Rick James    schedule 16.10.2019
comment
Это локальная машина с 32 ГБ оперативной памяти, которую я мог бы использовать для виртуального диска. Мне нужно постоянно выполнять ЗАГРУЗКУ ДАННЫХ (всякий раз, когда доступны новые данные). Примерно каждые 6ч.   -  person membersound    schedule 16.10.2019
comment
Запрос дополнительной информации. Опубликуйте на pastebin.com и поделитесь ссылками. # ядра вашего хост-сервера MySQL Из корня входа SSH, текстовые результаты: B) SHOW GLOBAL STATUS; минимум через 24 часа UPTIME C) ПОКАЗАТЬ ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ; D) ПОКАЗАТЬ ПОЛНЫЙ СПИСОК ПРОЦЕССОВ; E) полный отчет MySQLTuner И необязательная очень полезная информация, если она доступна, включает - htop ИЛИ top ИЛИ mytop для наиболее активных приложений, ulimit -a для списка ограничений linux/unix, iostat -xm 5 3 для IOPS по устройствам и ядрам/процессорам count, для анализа настройки рабочей нагрузки сервера, чтобы предоставить предложения.   -  person Wilson Hauck    schedule 06.11.2019


Ответы (2)


Механизм MySQL/MariaDB мало распараллеливается при массовых вставках. Он может использовать только одно ядро ​​ЦП на оператор LOAD DATA. Вы, вероятно, можете контролировать загрузку ЦП во время загрузки, чтобы увидеть, что одно ядро ​​​​используется полностью, и оно может предоставить только определенный объем выходных данных, таким образом оставляя пропускную способность диска недоиспользованной.

В самой последней версии MySQL появилась новая функция параллельной загрузки: https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-utilities-parallel-table.html . Это выглядит многообещающе, но, вероятно, еще не получило много отзывов. Я не уверен, что это поможет в вашем случае.

Я видел различные контрольные списки в Интернете, которые рекомендовали иметь более высокие значения в следующих параметрах конфигурации: log_buffer_size, log_file_size, write_io_threads, bulk_insert_buffer_size. Но преимущества были не очень заметны, когда я проводил сравнительные тесты (может быть, на 10-20% быстрее, чем просто innodb_buffer_pool_size, будучи достаточно большим).

person ichalov    schedule 09.10.2019

Это может быть нормально. Давайте пройдемся по тому, что делается:

  • CSV-файл считывается с RAM-диска, поэтому IOP не используются.
  • Вы используете InnoDB? Если это так, данные попадают в пул буферов. Когда блоки строятся там, они помечаются как «грязные» для возможного сброса на диск.
  • Так как buffer_pool большой, но, вероятно, не такой большой, как таблица, некоторые блоки должны быть сброшены, прежде чем он закончит чтение всех данных.
  • После чтения всех данных и завершения работы с таблицей грязные блоки будут постепенно сбрасываться на диск.
  • Если бы у вас были неуникальные индексы, они аналогичным образом записывались бы на диск с задержкой (см. «Изменить буферизацию»). Change_buffer по умолчанию занимает 25% пула буферов.

Насколько велика результирующая таблица? Он может быть значительно больше или даже меньше, чем 15 ГБ CSV-файла.

Сколько времени ушло на перенос csv-файла на рам-диск? Я предполагаю, что это было потрачено впустую, и его нужно было прочитать с диска при выполнении LOAD DATA; что ввод-вывод может перекрываться.

Пожалуйста SHOW GLOBAL VARIABLES LIKE 'innodb%';; есть несколько других, которые могут иметь значение.

Еще

Это ужасно:

tmp_table_size=20G
max_heap_table_size=20G

Если у вас сложный запрос, в оперативной памяти может быть выделено 20 ГБ, возможно, несколько раз!. Держите их на уровне менее 1% ОЗУ.

Если копирование csv с жесткого диска на оперативный диск выполняется медленно, я подозреваю, что допустима скорость 150 МБ/с.

Если вы загружаете таблицу раз в 6 часов, а на ее выполнение уходит 1/3 часа, то не вижу острой необходимости делать ее быстрее. OTOH, может быть, есть что-то, на что стоит обратить внимание. Если эти 20 минут простоя из-за блокировки стола, это можно легко устранить:

CREATE TABLE t LIKE real_table;
LOAD DATA INFILE INTO t ...;    -- not blocking anyone
RENAME TABLE real_table TO old, t TO real_table;  -- atomic; fast
DROP TABLE old;
person Rick James    schedule 15.10.2019
comment
Я обновил все переменные my.cnf, которые я изменил по умолчанию. Я обнаружил, что тот же процесс LOAD выполняется в 4 раза быстрее, если я использую только несколько столбцов, но с таким же объемом данных. Так что, к сожалению, количество столбцов кажется узким местом. Но почему? Могу ли я улучшить это в любом случае? - person membersound; 16.10.2019
comment
@membersound - Интересное наблюдение! Рассмотрите возможность загрузки в меньшее количество столбцов, а затем напишите INSERT ... SELECT ... , чтобы разделить поля и поместить их в другую таблицу. (Нет, я не знаю, будет ли это быстрее.) - person Rick James; 17.10.2019