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

14

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 (la croissance du fichier de la table file_per_tableest activée).

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.

David Parks
la source

Réponses:

7

OBSERVATION # 1

J'ai remarqué que vous vous étiez éteint 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 empêcher 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 de nombreuses données fantômes . Au fur et à mesure que ces deux choses augmentent, vous devriez 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 KEYSarrê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 manière linéaire sur la table et ajoutés à la .MYD.
  • InnoDB: comme le montre l'image interne d'InnoDB, le tablespave système ibdata1a une structure dédiée aux insertions d'index secondaire. À l'heure actuelle, il n'existe aucune disposition pour gérer les index comme 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 24 à 25 fois plus rapide? Exécutez ensuite ce qui suit:

ALTER TABLE item_load ROW_FORMAT=Fixed;

Cela accélérera les INSERTs de 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 exécuter cela sur une table InnoDB, mais le comportement conforme à ACID et MVCC d'InnoDB constitueraient toujours le goulot d'étranglement de ses performances, en particulier si les champs VARCHAR augmentent de manière significative sont écrits ibdata1.

RolandoMySQLDBA
la source
Les 2 premières observations ont été des choses que j'ai essayé d'ajouter pour résoudre le problème après l'avoir remarqué, ma première tentative a été naturellement de laisser innodb seul (il suffit de désactiver la journalisation du bac). Sur la 3ème observation, la taille de mes données est très variable en longueur, je suppose que ce sera un problème? Je sens que j'ai juste besoin de garder cette table myisam.
David Parks
6

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 considérer 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.

David Parks
la source
5

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

bnadland
la source
Mes fichiers sont déjà en morceaux de 500 Mo, je les canalisais tous à travers un seul tube nommé pour faciliter le chargement, mais je vais essayer cette approche maintenant.
David Parks
Ne voyant aucune différence ici, je vois assez rapidement la vitesse de l'expansion de 11 Mo / s du fichier DB à 6 Mo (après environ 2 Go) de données et elle continue de baisser. Je charge tous les fichiers dans une boucle for, des appels mysql séparés.
David Parks
Le premier fichier chargé en 54s, 2e en 3m39s, 3e en 3m9s, 4m7s, 5m21s, etc. tous les fichiers sont de la même taille.
David Parks
2

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 alors 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

KKYadav
la source