повільна швидкість завантаження даних з 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
Те, що ви хочете, ви знали, перш ніж намагатися завантажити базу даних 80gig з дампа через 4 дні після натискання "enter" ... :)
Дмитрій БД

7

На додаток до відповіді Абдула , я хотів би підкреслити важливість --disable-keysопції, яка вимикає клавіші, поки всі дані не завантажуються в таблицю. Цей параметр увімкнено як частина --optперемикання, яке включено за замовчуванням, але вважається важливим вказати.

Якщо ви не пропускаєте клавіші під час вставок, то кожен вставлений рядок відновить індекс. Надзвичайно повільний процес.


це --disable-ключі частина 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"

якщо файли gzipped перед натисканням на mysql, нічого не сповільнюється, в основному, через зниження вводу / виводу. Мої таблиці були стиснуті приблизно до 10: 1, тому це економить багато місця на диску.

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

Ще деякі речі, які слід зазначити. Якщо у вас 4-секторові накопичувачі, переконайтеся, що у вас є 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 про налаштування bulk_insert_buffer_size :

MyISAM використовує спеціальний кешоподібний кеш для того, щоб зробити масові вставки швидшими для INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., and 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. Я також підрахував, що перезавантаження mysqldump InnoDB повинно зайняти 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. зупинити mysqld
  2. перенести існуючий вміст / var / lib / mysql
  3. створити порожній / var / lib / mysql реж
  4. mount -t tmpfs -o size = 32 г tmpfs / var / lib / mysql (регулювання розміру)
  5. створити порожній db (наприклад, mysql_install_db або відновити попередній вміст)
  6. почати mysqld
  7. імпорт
  8. зупинити mysqld
  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-ядерному Xeon 3,2 ГГц.

Якщо вам не вистачає оперативної пам’яті в одній машині, але у вас кілька комп'ютерів поруч із швидкою мережею, було б цікаво дізнатись, чи можна їх оперативної пам’яті з'єднати з nbd (мережевим блоковим пристроєм). Або, використовуючи innodb_file_per_table, ви, ймовірно, можете повторити описаний вище процес для кожної таблиці.


З цікавості я спробував зберегти mysql datadir в оперативній пам'яті, щоб порівняти його з SSD (SSDSC2BB48 для зацікавлених) для бази даних 2 Гб. Результати були ІДЕНТИЧНІ, обидва вони зайняли 207-209 секунд. Враховуючи той факт, що вам також доведеться запускати / зупиняти mysql та копіювати каталоги, використання моменту оперативної пам’яті замість SSD в моєму випадку було набагато повільніше
Shocker

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