web-dev-qa-db-fra.com

MySQL LOAD DATA INFILE ralentit de 80% après quelques concerts avec le moteur InnoDB

Je charge un fichier de 100 Go via LOAD DATA INFILE. J'ai eu un bon succès avec MyISAM, quelques heures et c'est fait.

J'essaye maintenant en utilisant InnoDB. La charge démarre rapidement à plus de 10 Mo/s (en regardant la croissance du fichier de table, file_per_table est activé).

Mais après environ 5 Go de données, il ralentit à une plage de 2 à 4 Mo/s, alors que j'obtiens plus de 20 Go, il a baissé d'environ 2 Mo/s.

La taille des pools de mémoire tampon InnoDB est de 8G. Et j'ai fait ce qui suit avant d'exécuter la commande LOAD DATA INFILE:

SET @@session.sql_log_bin=0;
SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;
alter table item_load disable keys;
//Run LOAD DATA INFILE....

Je ne vois pas pourquoi cela démarre bien et ralentit avec le temps.

De plus, en utilisant les mêmes paramètres, j'ai exécuté la même commande LOAD DATA INFILE avec la table en utilisant InnoDB et MyISAM et un ensemble de données de test de 5 Go, MyISAM était 20 fois plus rapide:

InnoDB:

mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 2630886 rows affected, 6 warnings (21 min 25.38 sec)
Records: 2630886  Deleted: 0  Skipped: 0  Warnings: 6

MyISAM:

mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 2630886 rows affected, 6 warnings (1 min 2.52 sec)
Records: 2630886  Deleted: 0  Skipped: 0  Warnings: 6

Autre chose que je devrais envisager d'essayer? Le moteur MyISAM est capable de maintenir le taux de charge beaucoup mieux.


Détails supplémentaires:

  • J'ai essayé de charger les fichiers individuellement, aucune différence.

  • Soit dit en passant, j'ai 150 fichiers de 500 Mo chacun, dans chaque fichier les clés sont triées.

  • Après avoir obtenu 40 Go en une nuit, 12 heures plus tard, le taux de charge est tombé à 0,5 Mo/s, ce qui signifie que l'opération est pratiquement impossible.

  • Je n'ai trouvé aucune autre réponse à des questions similaires sur d'autres forums, il me semble qu'InnoDB ne prend pas en charge le chargement de grandes quantités de données dans des tableaux de plus de quelques Go.

14
David Parks

OBSERVATION # 1

J'ai remarqué que vous avez désactivé autocommit. Cela accumulera tellement de données dans ibdata1. Pourquoi?

Il existe sept (7) classes d'informations stockées dans ibdata1:

  • Pages de données pour les tables InnoDB
  • Pages d'index pour les tables InnoDB
  • Dictionnaire de données
  • Tampon d'écriture double
    • Un filet de sécurité pour prévenir la corruption des données
    • Aide à contourner le système d'exploitation pour la mise en cache
  • Insérer un tampon (rationalise les modifications apportées aux index secondaires)
  • Segments de restauration
  • Annuler les journaux
  • Cliquez ici pour voir une représentation picturale de ibdata1

Certaines de ces informations sont rendues visibles pour certaines transactions en fonction du niveau d'isolement. De telles actions pourraient produire des verrous de clé primaire involontaires et beaucoup de fantômes données . Au fur et à mesure que ces deux choses augmentent, vous devez vous attendre à un léger ralentissement.

Recommandation: Laissez la validation automatique activée

OBSERVATION # 2

Je vois que vous avez ceci:

alter table item_load disable keys;

DISABLE KEYS ne fonctionne pas avec InnoDB . Voici pourquoi:

  • MyISAM: DISABLE KEYS arrête simplement la mise à jour de l'index secondaire pour la table MyISAM. Lorsque vous insérez en masse dans une table MyISAM avec les clés désactivées, le chargement de la table est rapide ainsi que la construction de la PRIMARY KEY et de tous les index uniques. Lorsque vous exécutez ENABLE KEYS, tous les index secondaires sont construits de façon linéaire sur la table et ajoutés au .MYD.
  • InnoDB: comme le montre l'image interne d'InnoDB, le tablespave système ibdata1 a une structure dédiée aux insertions d'index secondaire. À l'heure actuelle, il n'existe aucune disposition pour gérer les index de la même manière que MyISAM.

Pour illustrer cela, notez ma tentative d'exécuter DISABLE KEYS sur une table InnoDB dans MySQL

mysql> show create table webform\G
*************************** 1. row ***************************
       Table: webform
Create Table: CREATE TABLE `webform` (
  `nid` int(10) unsigned NOT NULL,
  `confirmation` text NOT NULL,
  `confirmation_format` tinyint(4) NOT NULL DEFAULT '0',
  `redirect_url` varchar(255) DEFAULT '<confirmation>',
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `block` tinyint(4) NOT NULL DEFAULT '0',
  `teaser` tinyint(4) NOT NULL DEFAULT '0',
  `allow_draft` tinyint(4) NOT NULL DEFAULT '0',
  `submit_notice` tinyint(4) NOT NULL DEFAULT '1',
  `submit_text` varchar(255) DEFAULT NULL,
  `submit_limit` tinyint(4) NOT NULL DEFAULT '-1',
  `submit_interval` int(11) NOT NULL DEFAULT '-1',
  PRIMARY KEY (`nid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> alter table webform disable keys;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+-------------------------------------------------------------+
| Level | Code | Message                                                     |
+-------+------+-------------------------------------------------------------+
| Note  | 1031 | Table storage engine for 'webform' doesn't have this option |
+-------+------+-------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select version();
+------------+
| version()  |
+------------+
| 5.5.27-log |
+------------+
1 row in set (0.00 sec)

mysql>

OBSERVATION # 3

Vous avez remarqué que MyISAM se charge 20 fois plus vite qu'InnoDB. Souhaitez-vous que ce soit plus 24 à 25 fois plus rapide? Exécutez ensuite ce qui suit:

ALTER TABLE item_load ROW_FORMAT=Fixed;

Cela accélérera les INSERTs fois 20-25% sans aucune autre modification DDL . Effet secondaire: la table MyISAM peut atteindre une taille de 80% à 100%, peut-être plus grande.

Vous pouvez également l'exécuter sur une table InnoDB, mais le comportement conforme à ACID et [~ # ~] mvcc [~ # ~] d'InnoDB serait toujours le goulot d'étranglement de ses performances, surtout si les champs VARCHAR augmentent de manière significative sont écrits dans ibdata1.

7
RolandoMySQLDBA

La réponse finale à cette question était de ne pas utiliser InnoDB pour une table de référence massive. MyISAM crie rapidement, presque à plein débit de la vitesse du disque pour toute la charge, InnoDB s'embourbe. MyISAM est simple, mais dans ce cas, les exigences de ce tableau le sont également. Pour une table de référence simple avec des charges en vrac sur LOAD DATA INFILE, MyISAM est la voie à suivre, jusqu'ici tout va bien.

Mais notez que si vous exécutez les tables MyISAM et InnoDB, vous devrez prendre en compte l'allocation de mémoire pour 2 mécanismes de mise en cache, chaque moteur a sa propre mise en cache unique qui nécessite une allocation de mémoire distincte.

6
David Parks

Vous pouvez essayer de diviser vos fichiers d'entrée en plus petits morceaux.

J'utilise personnellement http://www.percona.com/doc/percona-toolkit/2.1/pt-fifo-split.html pour cela.

Que se passe-t-il si vous obtenez un verrou de table pour la table lors de l'importation? Peut-être que le verrouillage au niveau des lignes d'InnoDB le ralentit (MyISAM utilise un verrou de table).

Vous pouvez également lire ici pour d'autres idées: http://derwiki.tumblr.com/post/24490758395/loading-half-a-billion-rows-into-mysql

5
bnadland

Si votre PK n'est pas AUTO_INCREMENT ou si les données du fichier csv ne sont pas triées sur PK, cela peut affecter les performances de la charge de données. Étant donné que la table dans MySQL est un index, toutes les données sont stockées dans l'ordre trié, si la valeur PK n'est pas sur AUTO_INCREMENT, MySQL doit faire beaucoup de décalage de données pour obtenir les données stockées dans l'ordre trié. C'est la raison du chargement plus lent des données lorsque la taille de la table commence à augmenter.

Je charge un fichier csv de 91 Go avec PK sur AUTO_INCREMENT en utilisant LOAD DATA INFILE et je ne vois aucune baisse de mon débit. J'obtiens 140K à 145K inserts par seconde. Utilisation de Percona MySQL 5.6.38

2
KKYadav