vitesse de chargement lente des données de mysqldump

21

J'ai une base de données MySQL de taille moyenne avec environ 30 tables, dont 10 millions d'enregistrements, 100 millions. Le mysqldumpde toutes les tables (dans des fichiers séparés) est assez rapide, prend peut-être 20 minutes. Il génère environ 15 Go de données. Les fichiers les plus volumineux sont de l'ordre de 2 Go.

Lorsque je charge les données dans MySQL sur une autre boîte, une machine à six cœurs et 8 Go, cela prend une éternité. Facilement 12 heures d'horloge ou plus.

Je lance juste le client mysql pour charger le fichier, c'est à dire

mysql database < footable.sql

directement avec le fichier directement depuis mysqldump

mysqldump database foo > footable.sql

De toute évidence, je fais quelque chose de mal. Par où dois-je commencer pour qu'il puisse se terminer dans un délai raisonnable?

Je n'utilise aucun interrupteur sur le vidage ou la charge.

Pat Farrell
la source
Vous pouvez également désactiver la journalisation binaire pendant le chargement de votre vidage
Cédric PEINTRE

Réponses:

22

Prenez ces quelques points en considération, ils peuvent vous aider en cas de génération du vidage et de restauration.

  1. Utilisation Extended insertsdans les décharges.
  2. Vider le --tabformat afin que vous puissiez l'utiliser mysqlimport, ce qui est plus rapide que mysql < dumpfile.
  3. Importez avec plusieurs threads, un pour chaque table.
  4. Utilisez un moteur de base de données différent si possible. l'importation dans un moteur fortement transactionnel comme innodb est extrêmement lente. L'insertion dans un moteur non transactionnel comme MyISAM est beaucoup plus rapide.
  5. Désactivez les vérifications de clé étrangère et activez la validation automatique.
  6. Si vous importez vers innodb, la chose la plus efficace que vous puissiez faire est de mettre innodb_flush_log_at_trx_commit = 2votre my.cnf, temporairement pendant que l'importation est en cours. vous pouvez le remettre à 1 si vous avez besoin d'ACIDE

Essaie..

Abdul Manaf
la source
Votre indice avec innodb_flush_log_at_trx_commit = 2sauvé ma journée. L'importation d'un vidage de 600 Mo (comme une seule grosse transaction) aurait nécessité 6 heures, mais avec ce paramètre temporaire, cela s'est fait en 30 minutes!
Daniel Marschall
1
Les choses que vous souhaitiez savoir avant d'essayer de charger une base de données 80gig à partir d'un vidage 4 jours après avoir cliqué sur 'enter' ... :)
Dmitri DB
7

En plus de la réponse d' Abdul , je voudrais souligner l'importance de l' --disable-keysoption, qui désactive les clés jusqu'à ce que toutes les données soient chargées pour une table. Cette option est activée dans le cadre de la --optbascule, qui est activée par défaut, mais il est important de le souligner.

Si vous ne sautez pas de clés pendant les insertions, chaque ligne insérée reconstruira l'index. Un processus extrêmement lent.

Derek Downey
la source
--disable-keys fait-il partie de mysqldump? ou le rechargement?
Pat Farrell
il sera ajouté dans le fichier de vidage
Derek Downey
--optest
activé
1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Ethan Allen
7

J'en ai beaucoup traité récemment. Vous pouvez certainement améliorer les performances d'importation en effectuant les importations en parallèle. La plupart du ralentissement est basé sur les E / S, mais vous pouvez toujours obtenir une amélioration de 40% en effectuant un dumping dans les tables, puis en les important, disons 4 à la fois.

Vous pouvez le faire avec des xargs comme celui-ci:

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

le fait de compresser les fichiers avant de les pousser vers mysql ne ralentit rien, principalement à cause des E / S réduites. Mes tables ont été compressées jusqu'à environ 10: 1, ce qui permet d'économiser beaucoup d'espace disque.

J'ai trouvé que sur 4 machines de base, l'utilisation de 4 processus est optimale, bien que seulement légèrement meilleure que l'utilisation de 3. Si vous avez des SSD ou un RAID rapide, vous évoluerez probablement mieux.

Quelques autres choses à noter. Si vous avez 4k lecteurs du secteur, assurez - vous que vous avez key_cache_block_size=4096etmyisam_block_size=4K .

Si vous utilisez des tables MyISAM, définissez le myisam_repair_threads = 2 ou supérieure. Cela permettra à vos cœurs supplémentaires d'aider à reconstruire les index.

Assurez-vous que vous n'échangez pas du tout. Si vous l'êtes, réduisez la taille duinnodb_buffer_pool_size .

Je pense que j'ai également accéléré avec innnodb par ces options:

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

(les trois derniers, je n'ai pas testé intensivement - je pense que je les ai trouvés comme suggestions sur les internets.) Notez que cela innodb_flush_log_at_commit=0peut entraîner une corruption avec le crash de mysql ou une panne de courant.

Greg
la source
Greg, bienvenue sur le site et merci pour votre réponse. Pourriez-vous fournir des sources ou un raisonnement pour vos suggestions sur *_block_sizeet myisam_repair_threads? De plus, je ne suis pas sûr que nous devrions offrir des conseils pour régler les variables en fonction des «suggestions des internets» :)
Derek Downey
5

Si vous avez principalement des tables MyISAM, vous devez augmenter le tampon d'insertion en bloc . Voici ce que dit la documentation MySQL sur la définition de bulk_insert_buffer_size :

MyISAM utilise un cache en forme d'arbre spécial pour accélérer les insertions en bloc pour INSERT ... SELECT, INSERT ... VALUES (...), (...), ... et LOAD DATA INFILE lors de l'ajout de données à non vide les tables. Cette variable limite la taille de l'arborescence du cache en octets par thread. Le mettre à 0 désactive cette optimisation. La valeur par défaut est 8 Mo.

Il y a deux choses que vous devez faire

1) Ajoutez-le à /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Définissez sa valeur globale

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Si vous n'avez pas le privilège de définir globalement bulk_insert_buffer_size, procédez comme suit

service mysql restart

Bien sûr, ce n'est pas pour InnoDB.

Sous un autre angle, que les tables soient InnoDB ou MyISAM, si les index sont plus grands que la table, vous pouvez avoir trop d'index. Je pense généralement qu'un rechargement d'un MyISAM mysqldump devrait prendre 3 fois plus de temps que le mysqldump a pris. Je pense également qu'un rechargement d'un mysqldump InnoDB devrait prendre 4 fois plus de temps que le mysqldump a pris.

Si vous dépassez le ratio 4: 1 pour recharger un mysqldump, vous avez certainement l'un des deux problèmes suivants:

  • trop d'index
  • index juste trop grands en raison de grandes colonnes

Vous pouvez mesurer la taille de vos données par moteur de stockage avec ceci:

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;

Voyez si les index sont presque aussi gros que les données ou même plus gros

Vous pouvez également envisager de désactiver la journalisation binaire comme ceci:

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

avant de recharger le script

RolandoMySQLDBA
la source
Je ne sais pas combien de fois vous avez sauvé ma journée, mais cela a certainement été beaucoup
Dmitri DB
2

Si vous contournez complètement le système de fichiers et que vous dirigez simplement la sortie de mysqldump directement dans un processus MySQL, vous devriez voir des améliorations de performances notables. La quantité dépend finalement du type de lecteur de disque que vous utilisez, mais j'utilise rarement les fichiers de vidage, quelle que soit la taille de la base de données, pour cette seule raison.

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy
Marcus Pope
la source
1

D'après mes expériences, le disque dur est le goulot d'étranglement. Oubliez les disques en rotation. Le SSD est meilleur, mais de loin le mieux est de le faire en RAM - si vous en avez assez pour contenir la base de données entière pendant un court instant. Grossièrement:

  1. arrêtez mysqld
  2. déplacer le contenu existant de / var / lib / mysql
  3. créer un répertoire / var / lib / mysql vide
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql (ajustez la taille)
  5. créer une base de données vide (par exemple mysql_install_db, ou restaurer le contenu précédent)
  6. démarrer mysqld
  7. importation
  8. arrêtez mysqld
  9. copier / var / lib / mysql vers mysql2
  10. umount mysql; rmdir mysql
  11. déplacer mysql2 vers mysql
  12. lancez mysqld, soyez heureux

Pour moi, un vidage de ~ 10G (/ var / lib / mysql consommant ~ 20G) peut être importé en environ 35 minutes (mydumper / myloader), 45 minutes (mysqldump --tab / mysqlimport), 50 minutes (mysqldump / mysql) , sur un Xeon 2x6 à 3,2 GHz.

Si vous n'avez pas assez de RAM sur une seule machine, mais que vous avez plusieurs ordinateurs côte à côte avec un réseau rapide, il serait intéressant de voir si leurs RAM peuvent être jointes avec nbd (périphérique de bloc réseau). Ou, avec innodb_file_per_table, vous pouvez probablement répéter le processus ci-dessus pour chaque table.

egmont
la source
Par curiosité, j'ai essayé de stocker le datadir mysql dans la RAM pour le comparer avec un SSD (SSDSC2BB48 pour les intéressés) pour une base de données de 2 Go. Les résultats étaient IDENTIQUES, les deux ont pris 207-209 secondes. Compte tenu du fait que vous devez également démarrer / arrêter mysql et copier les répertoires, l'utilisation d'un disque RAM au lieu du SSD a été beaucoup plus lente dans mon cas
Shocker
Si cela vous a pris ~ 3-4 minutes, je suppose que votre base de données est beaucoup plus petite que ce dont traite ce sujet. Il serait intéressant d'entendre parler de vos expériences avec des bases de données de taille similaire à celles mentionnées dans cette rubrique.
egmont