Vitesse d'insertion pour les grands lots


10

Dans ma candidature, mes INSERT semblent prendre une grande partie du temps. J'ai un grand nombre d'objets en mémoire (~ 40-50 000) que je souhaite insérer dans une table.

Prenons un exemple de table

CREATE TABLE bill (
id BIGINT(20) PRIMARY KEY,
amount INT(11) DEFAULT 0,
bill_date DATETIME DEFAULT NOW(),
INDEX (bill_date)
) ENGINE=InnoDB

En prenant 3 lignes comme taille de lot, voici les approches auxquelles je pourrais penser pour insérer

Approche 1 - construire et cuire 3 inserts bruts

INSERT INTO bill (amount, bill_date) VALUES (10, '2012-01-01 00:00:00');
INSERT INTO bill (amount, bill_date) VALUES (20, '2012-01-02 00:00:00');
INSERT INTO bill (amount, bill_date) VALUES (40, '2013-02-05 00:00:00');

Approche 2 - regrouper les valeurs en 1 requête

INSERT INTO bill (amount, bill_date) VALUES 
(10, '2012-01-01 00:00:00'),
(20, '2012-01-02 00:00:00'),
(40, '2013-02-05 00:00:00');

Approche 3 - lancer cette requête 1 fois en passant 6 paramètres

INSERT INTO bill (amount, bill_date) VALUES 
(?, ?), (?, ?), (?, ?);

Approche 4 - Lancer cette requête préparée 3 fois en changeant les 2 paramètres à chaque fois

INSERT INTO bill (amount, bill_date) VALUES (?, ?);

Toute autre approche est la bienvenue.

Ma question est

Quelle est la façon la plus rapide de créer plusieurs insertions dans une table?

J'ai lu ce lien sur la vitesse d'insertion mysql et ce guide de programmation JDBC , mais je ne suis pas en mesure de conclure.

Mon cas -

Actuellement, ma table a environ 20 colonnes, dont la plupart sont des nombres, avec quelques varchar (60) et 1 colonne de texte. Mysql version 5.5. Fonctionnant sur INNODB et possède 1 index sur les clés primaires entières. Toutes les requêtes s'exécutent en transaction.

Je construis mes requêtes à partir de Java et j'utilise Spring JDBC pour exécuter les requêtes.

Je suis actuellement en train de suivre l'approche 3, cela prend environ 10 secondes pour 20 000 insertions dans une table vide, sans compter le temps nécessaire pour construire la requête.

Pour garder les choses en perspective, il faut 100 à 200 millis pour récupérer les données de la table.

Y a-t-il quelque chose qui me manque? Comment accélérer les inserts?


Réponses:


3

Pensez à regrouper vos commits. Une taille de lot de 1024 est une bonne taille de départ. Modifiez la taille des lots jusqu'à atteindre votre débit optimal.


1

Avez-vous testé ou serait-il possible de supprimer des index sur la ou les tables de base de données de destination dans lesquelles vous les insérez, de les insérer dans des blocs plus petits (optimaux comme indiqué ci-dessus), puis de reconstruire les index sur la ou les tables de destination une fois tous les inserts terminés? Peut être quelque chose d'assez facile à tester pour confirmer.


0

Certains conseils de chargement de données en masse à partir du document mysql peuvent être utiles. https://dev.mysql.com/doc/refman/5.6/en/optimizing-innodb-bulk-data-loading.html

Vous pouvez augmenter la vitesse d'insertion de plusieurs manières:

- turn off autocommit
- turn off unique check
- turn off foreign check

J'espère que cette aide!


2
Si vous désactivez les contrôles de contraintes (unique, clé étrangère, ...), assurez-vous que vos données ne les cassent pas ou que votre base de données est dans un état incohérent à partir de ce moment.
David Spillett
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.