Pourquoi jdbcTemplate.batchUpdate () de Spring est-il si lent?
J'essaie de trouver le plus rapide pour faire de lot insérer.
J'ai essayé d'insérer plusieurs lots avec jdbcTemplate.mise à jour(String sql)où
sql a été construite par StringBuilder et ressemble:
INSERT INTO TABLE(x, y, i) VALUES(1,2,3), (1,2,3), ... , (1,2,3)
La taille des lots a été exactement 1000. J'ai inséré près de 100 lots.
J'ai vérifié le temps à l'aide d'un Chronomètre et un découvert l'heure d'insertion:
min[38ms], avg[50ms], max[190ms] per batch
J'étais content mais j'ai voulu faire de mon mieux.
Après cela, j'ai essayé d'utiliser jdbcTemplate.batchUpdate en sorte, comme:
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
//...
}
@Override
public int getBatchSize() {
return 1000;
}
});
où sql a été ressembler
INSERT INTO TABLE(x, y, i) VALUES(1,2,3);
et j'ai été déçu! jdbcTemplate exécuté à chaque insert unique de 1000 lignes de lots dans des locaux séparés. Je loked à mysql_log et trouvé il y a un millier d'inserts.
J'ai vérifié le temps à l'aide d'un Chronomètre et un découvert l'heure d'insertion:
min[900ms], avg[1100ms], max[2000ms] par Lot
Donc, quelqu'un peut-il m'expliquer, pourquoi jdbcTemplate faire séparées insère dans cette méthode? Pourquoi la méthode est le nom de batchUpdate?
Ou peut-être que je suis à l'aide de cette méthode dans le mauvais sens?
source d'informationauteur user2602807
Vous devez vous connecter pour publier un commentaire.
Ces paramètres de la connexion JDBC URL peut faire une grande différence dans la vitesse de lots consolidés --- dans mon expérience, ils accélérer les choses:
Voir: JDBC lot performance de l'insert
J'ai aussi été confronté au même problème avec Spring JDBC modèle. Probablement avec Spring Batch la déclaration a été signée, et engagé sur chaque insertion ou sur des morceaux, qui a ralenti les choses.
J'ai remplacé le jdbcTemplate.batchUpdate() code d'origine avec JDBC lot code d'insertion et trouvé le Majeur d'amélioration de la performance.
Vérifier ce lien
JDBC lot performance de l'insert
Changer votre sql insert à
INSERT INTO TABLE(x, y, i) VALUES(1,2,3)
. Le cadre crée une boucle pour vous.Par exemple:
SI vous avez quelque chose comme cela. Le printemps va faire quelque chose comme:
Le cadre de la première crée PreparedStatement à partir de la requête (la
sql
variable) puis le setValues méthode est appelée et de l'instruction est exécutée. qui est répété autant de fois que vous spécifiez dans lagetBatchSize()
méthode. Donc la bonne façon d'écrire l'instruction insert est avec une seule clause values.Vous pouvez prendre un coup d'oeil à http://docs.spring.io/spring/docs/3.0.x/reference/jdbc.html
Simplement utiliser la transaction. Ajouter @Transactional sur la méthode.
Assurez-vous de déclarer le bon TX gestionnaire de cas à l'aide de plusieurs sources de données @Transactionnelle("dsTxManager"). J'ai un cas où l'insertion de 60000 enregistrements. Il faut environ 15 ans. Aucun autre tweak:
Je ne sais pas si cela fonctionne pour vous, mais ici, c'est un Printemps sans que j'ai fini de l'utiliser. Il était nettement plus rapide que les différentes Printemps méthodes que j'ai essayé. J'ai même essayé d'utiliser le JDBC lot de modèle de mise à jour de la méthode de la réponse à décrire, mais même qui a été plus lente que ce que je voulais. Je ne suis pas sûr de ce qui se passait et les Internets n'ai pas eu beaucoup de réponses. Je me doutais qu'il avait à faire avec la façon dont s'engage étaient traités.
Cette approche est tout simple à l'aide de JDBC java.sql paquets et PreparedStatement de lot de l'interface. C'était le moyen le plus rapide que j'ai pu obtenir 24M des enregistrements dans une base MySQL.
J'ai plus ou moins juste construit les collections de "record" des objets et a ensuite appelé le code ci-dessous dans une méthode lot inséré tous les enregistrements. La boucle qui construit les collections a été responsable de la gestion de la taille des lots.
J'ai essayé d'insérer 24M des enregistrements dans une base MySQL et il allait ~200 enregistrements par seconde à l'aide de Spring batch. Quand je suis passé à cette méthode, il est allé jusqu'à ~2500 enregistrements par seconde. donc, mon 24M chargement record est allé théorique de 1,5 jours à environ 2,5 heures.
D'abord créer une connexion...
Puis créer une déclaration préparée à l'avance et de les charger avec des lots de valeurs pour insérer, puis exécuter en un seul lot insert...
Évidemment, j'ai retiré la gestion d'erreur et de la requête et de l'objet d'Enregistrement est fictive et autres joyeusetés.
Edit:
Depuis votre question initiale était de comparer les insérer dans foobar valeurs (?,?,?), (?,?,?)...(?,?,?) méthode de Spring batch, voici une réponse plus directe:
Il ressemble à la méthode originale est probablement le moyen le plus rapide pour faire de vrac chargements de données dans MySQL sans l'aide de quelque chose comme le "LOAD DATA INFILE" approche. Une citation de l'MysQL docs (http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html):
Vous pourriez modifier le Printemps JDBC Modèle batchUpdate méthode pour faire un insert avec plusieurs VALEURS spécifiées par "setValues' appel, mais vous auriez à assurer le suivi manuel des valeurs de l'indice que vous effectuer une itération sur l'ensemble des choses en cours d'insertion. Et que vous souhaitez exécuter dans un mauvais cas de bord à la fin, quand le nombre de choses étant inséré n'est pas un multiple du nombre de listes de VALEURS que vous avez dans votre déclaration.
Si vous utilisez l'approche que j'ai aperçu, vous pourriez faire la même chose (l'utilisation d'une requête préparée avec de multiples listes de VALEURS) et puis, quand vous obtenez à bord à la fin, c'est un peu plus facile parce que vous pouvez construire et exécuter une dernière déclaration avec exactement le bon nombre de listes de VALEURS. C'est très orthodoxe, mais le plus optimisé les choses sont.
J'ai trouvé un amélioration majeure réglage de la argTypes tableau dans l'appel.
Dans mon cas, avec le Printemps, 4.1.4 et Oracle 12c, pour l'insertion de 5000 lignes avec des 35 domaines:
La argTypes param est un tableau int lorsque vous définissez chaque champ de cette façon:
J'ai débogué org\springframework\jdbc\core\JdbcTemplate.java et a constaté que la plupart du temps a été consommé en essayant de connaître la nature de chaque champ, et cela a été fait pour chaque enregistrement.
Espérons que cette aide !