медленная скорость загрузки данных из mysqldump


21

У меня есть небольшая база данных MySQL с около 30 таблицами, некоторые из которых 10 миллионов записей, около 100 миллионов. Из mysqldumpвсех таблиц (в отдельных файлах) довольно быстро, может быть, занимает 20 минут. Он генерирует около 15 ГБ данных. Самые большие выгруженные файлы находятся в диапазоне 2 ГБ.

Когда я загружаю данные в MySQL на другой компьютер с шестью ядрами, 8 ГБ, это занимает вечность. Легко 12 часов или более часов.

Я просто запускаю клиент mysql для загрузки файла, т.е.

mysql database < footable.sql

напрямую с файлом напрямую из mysqldump

mysqldump database foo > footable.sql

Очевидно, я делаю что-то не так. С чего начать, чтобы закончить в разумные сроки?

Я не использую никаких переключателей ни на дампе, ни на нагрузке.


Вы также можете отключить бинарное ведение журнала во время загрузки вашего дампа
Cédric PEINTRE

Ответы:


22

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

  1. Используйте Extended insertsв свалках.
  2. Дамп с --tabформатом, чтобы вы могли использовать mysqlimport, что быстрее, чем mysql < dumpfile.
  3. Импорт с несколькими потоками, по одному для каждой таблицы.
  4. Если возможно, используйте другой движок базы данных. импорт в сильно транзакционный движок, такой как innodb, очень медленный. Вставка в нетранзакционный движок, такой как MyISAM, намного быстрее.
  5. Отключите проверку внешнего ключа и включите авто-фиксацию.
  6. Если вы импортируете в innodb, единственная наиболее эффективная вещь, которую вы можете сделать, - это innodb_flush_log_at_trx_commit = 2временно вставить ваш my.cnf во время выполнения импорта. Вы можете вернуть его на 1, если вам нужна кислота

Попробуйте ...


Твой намек на innodb_flush_log_at_trx_commit = 2спас мой день. Для импорта дампа размером 600 МБ (как одной большой транзакции) потребовалось бы 6 часов, но с этой временной настройкой это было сделано за 30 минут!
Даниэль Маршалл

1
Вещи, которые вы хотели бы знать, прежде чем пытаться загрузить 80-гигабайтную базу данных из дампа через 4 дня после нажатия «enter» ... :)
Дмитрий БД

7

В дополнение к ответу Абдула я хотел бы подчеркнуть важность --disable-keysопции, которая отключает ключи до тех пор, пока все данные не будут загружены для таблицы. Эта опция включена как часть --optпереключателя, который включен по умолчанию, но считает важным указать.

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


является --disable-keys частью mysqldump? или перезагрузка?
Пэт Фаррелл

это будет добавлено в файл дампа
Дерек Дауни

--optпо умолчанию
включен

1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Итан Аллен

7

Я много занимался этим в последнее время. Вы можете определенно улучшить производительность импорта, выполнив импорт параллельно. Большая часть замедления основана на вводе-выводе, но вы все равно можете получить улучшение на 40%, создавая дамп в таблицы, а затем импортируя их, скажем, 4 за раз.

Вы можете сделать это с помощью xargs следующим образом:

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

сжатие файлов перед их отправкой в ​​mysql ничего не замедляет, главным образом из-за сниженного ввода-вывода. Мои таблицы были сжаты примерно до 10: 1, поэтому это экономит много места на диске.

Я обнаружил, что на 4-х ядерных машинах оптимально использовать 4 процесса, хотя только незначительно лучше, чем 3. Если у вас SSD или быстрый RAID, вы, вероятно, будете лучше масштабироваться.

Некоторые другие вещи, чтобы отметить. Если у вас есть 4k сектора дисков, убедитесь, что у вас есть key_cache_block_size=4096и myisam_block_size=4K.

Если вы используете таблицы MyISAM, установите myisam_repair_threads = 2или выше. Это позволит вашим дополнительным ядрам помочь перестроить индексы.

Убедитесь, что вы не обмениваетесь вообще. Если да, уменьшите размер innodb_buffer_pool_size.

Я думаю, что я получил некоторое ускорение с помощью innnodb с помощью этих опций:

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(Последние три я не тестировал всесторонне - я думаю, что нашел их в качестве предложений в интернете.) Обратите внимание, что это innodb_flush_log_at_commit=0может привести к повреждению из-за сбоя mysql или отключения питания.


Грег, добро пожаловать на сайт и спасибо за ваш ответ. Не могли бы вы предоставить некоторые источники или обоснование ваших предложений по *_block_sizeи myisam_repair_threads? Кроме того, не уверен, что мы должны дать совет по настройке переменных на основе «предложений из интернета» :)
Дерек Дауни

5

Если у вас в основном таблицы MyISAM, вы должны увеличить буфер массовой вставки . Вот что говорит MySQL Documentation о настройке bulk_insert_buffer_size :

MyISAM использует специальный древовидный кэш, чтобы ускорить массовые вставки для INSERT ... SELECT, INSERT ... VALUES (...), (...), ... и LOAD DATA INFILE при добавлении данных в непустые столы. Эта переменная ограничивает размер дерева кэша в байтах на поток. Установка в 0 отключает эту оптимизацию. Значение по умолчанию составляет 8 МБ.

Есть две вещи, которые вам нужно сделать

1) Добавьте его в /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Установите глобальное значение для него

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Если у вас нет прав на глобальную настройку bulk_insert_buffer_size, сделайте это

service mysql restart

Конечно, это не для InnoDB.

С другой стороны, будь то таблицы InnoDB или MyISAM, если индексы больше, чем у таблицы, у вас может быть слишком много индексов. Я обычно предполагаю, что перезагрузка MyISAM mysqldump должна занять в 3 раза больше времени, чем потребовалось mysqldump. Я также предполагаю, что перезагрузка InnoDB mysqldump должна занять в 4 раза больше времени, чем потребовалось mysqldump.

Если вы превысили соотношение 4: 1 для перезагрузки mysqldump, у вас определенно есть одна из двух проблем:

  • слишком много индексов
  • слишком большие индексы из-за больших столбцов

Вы можете измерить размер ваших данных с помощью механизма хранения с помощью этого:

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

Посмотрите, являются ли индексы почти такими же большими, как данные или даже большими

Вы также можете отключить бинарное ведение журнала следующим образом:

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

перед перезагрузкой скрипта


Я не знаю, сколько раз вы спасли мой день, но это, безусловно, было очень много
Дмитрий Д.Б.

2

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

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy

1

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

  1. остановить MySQL
  2. убрать существующее содержимое / var / lib / mysql
  3. создать пустой каталог / var / lib / mysql
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql (изменить размер)
  5. создать пустую базу данных (например, mysql_install_db или восстановить предыдущее содержимое)
  6. начать MySQL
  7. импорт
  8. остановить MySQL
  9. скопируйте / var / lib / mysql в mysql2
  10. umount mysql; rmdir mysql
  11. переместить mysql2 в mysql
  12. начать mysqld, будь счастлив

Для меня дамп ~ 10G (/ var / lib / mysql, потребляющий ~ 20G) может быть импортирован за 35 минут (mydumper / myloader), 45 минут (mysqldump --tab / mysqlimport), 50 минут (mysqldump / mysql) , на 2x6-ядерном 3,2 ГГц Xeon.

Если у вас недостаточно ОЗУ на одной машине, но у вас есть несколько компьютеров рядом с быстрой сетью, было бы интересно посмотреть, можно ли объединить их ОЗУ с nbd (сетевым блочным устройством). Или, используя innodb_file_per_table, вы, вероятно, можете повторить описанный выше процесс для каждой таблицы.


Из любопытства я попытался сохранить datadir mysql в оперативной памяти, чтобы сравнить его с SSD (SSDSC2BB48 для заинтересованных) для базы данных объемом 2 ГБ. Результаты были ИДЕНТИЧНЫМИ, оба заняли 207-209 секунд. Учитывая тот факт, что вы также должны запускать / останавливать mysql и копировать каталоги, использование RAM-диска вместо SSD в моем случае было намного медленнее
Shocker

Если вам потребовалось ~ 3-4 минуты, я думаю, у вас значительно меньшая база данных, чем эта тема. Было бы интересно услышать о вашем опыте работы с такими же большими базами данных, как те, которые упомянуты в этой теме.
egmont
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.