samedi 9 mai 2009

Améliorer la performance de vos travaux de fin de journée par “JDBC Batch” et Spring

L’une des fonctionnalités la moins connu de JDBC est sa capacité à exécuter des opérations SQL par Lot en combinat les méthodes addBatch et executeBatch de Statement (et les autres variantes de Statement).

Je présente dans cette étude une expérience simple qui montre l’utilité, d’un point de vue temps de réponse globale, de l’exploitation judicieuse de cette fonctionnalité.

Exécution d'opérations par lot

Pour lors de la réalisation de mises à jour multiples d'une base de données, un grande nombre de pilote JDBC (Oraxcle, PostgrSQL, MS SQL) offre la possibilité de soumettre plusieurs mises à jour comme un seul travail, appelé également lot.

La méthode addBatch permet d'ajouter une commande.

La méthode executeBatch permet de soumettre toutes les commandes pour traitement.

Seules des instructions DDL (Data Definition Language, langage de définition de données) et DML (Data Manipulation Language, langage de manipulation de données) qui retournent un seul nombre de mises à jour peuvent être exécutées dans un lot.

La méthode executeBatch retourne un tableau de valeurs int correspondant au nombre de mises à jour de chaque commande.

JDBC et Exécution d'opérations par lot

Regroupement de plusieurs mises à jour:

connexion.setAutoCommit(false);

Statement st = connexion.createStatement();

st.addBatch("INSERT ..."); // Ajoute une requête SQL pour executeBatch

st.addBatch("UPDATE ..."); // Ajoute une requête SQL pour executeBatch

int[] nb = st.executeBatch(); // retourne le nombre de Mise à jour effectuées

Méthode « appropriée pour le codage » : exploiter l’abstraction de l’Ioc avec Spring

Je recommande d’utiliser la combinaison suivante

a) PreparedStatement

b) Spring templates pour les Batch updates

Ainsi, On peut combiner des « Prepared Statement » et des « Batch updates ».

DataSource dataSource = (DataSource) context.getBean("dataSource");

int nombreDefois = 2000;

int batchSize =10;

BatchInsert batchInsert = new BatchInsert(dataSource, batchSize);

testBatchInsert(nombreDefois, batchInsert);

///

private static void testBatchInsert(int count, BatchInsert batchInsert) throws DataAccessException {

for (int i = 0; i < count; i++) {

batchInsert.update(new Object[]{i + 10L, "a" + i, i});

}

}

100

String SQL_INSERT_ARTICLE = "INSERT INTO article(id,label,price)VALUES(?,?,?)";

BatchInsert(DataSource dataSource, int batchSize) {

super(dataSource, SQL_INSERT_ARTICLE);

declareParameter(new SqlParameter(Types.BIGINT));

declareParameter(new SqlParameter(Types.VARCHAR));

declareParameter(new SqlParameter(Types.NUMERIC));

setBatchSize(batchSize);

}

Outils de mesure :

Le plus simple c’est d’utiliser un profiler ou bien .

Dans cette présentation, j’ai utilisé NetBeans profiler version 6.5.1.

24 mesures ont été effectuées dans les conditions suivants

Un Laptop avec 2Go De RAM (les mesures n’ont pas de valeurs intrinsèques, c’est la comparaison des résutlats qui m’interesse)

Une base de données PostgrSQL sous Windows

La table est vidée après chaque exécution (avoir les mêmes conditions)

Les paramètres qui ont été variés

Le nombre d’insertion : de 100 à 10000

La valeur batchsize (taille du lots d’opérations SQL à batcher ) : de 1 à 200

Les résultats sont les suivants :

nombre de fois

Batchsize (ms)


1

10

50

200


336

223

215

-

500

914

386

281

253

1000

1627

792

349

320

2000

2867

760

485

446

5000

7801

1751

1022

871

10000

15901

2697

1529

1269

L’impact de

clip_image002

Ramené à l’unité : temps de réponse moyen d’une seule insertion

nombre de fois

Batchsize (ms) pour une seule insertion


1

10

50

200

100

3,36

2,23

2,15

-

500

1,828

0,772

0,562

0,506

1000

1,627

0,792

0,349

0,32

2000

1,4335

0,38

0,2425

0,223

5000

1,5602

0,3502

0,2044

0,1742

10000

1,5901

0,2697

0,1529

0,1269

clip_image004

Si on estime le gain en % de temps de réponse pour une insertion, on remarque l’impact de cette méthode sur le résultat final pour les grands nombre d’insertion (jusqu’à 90% !!).

gain en % en fonction du batchSize pour une seule insertion

nombre de fois

batchsize


1

10

50

200

100

3,36

33,6%

36,0%

-

500

1,83

57,8%

69,3%

72,3%

1000

1,63

51,3%

78,5%

80,3%

2000

1,43

73,5%

83,1%

84,4%

5000

1,56

77,6%

86,9%

88,8%

10000

1,59

83,0%

90,4%

92,0%

Observations annexes :

La création d’objets relatifs à l’opération JDBC, java.sql.*, permet de comprendre comment se passe les opérations.

Cas : batch size = 1 et 10000 insert

clip_image006

Cas : batch size = 50 et 10000 insert

clip_image008

Cas : batch size = 200 et 10000 insert

clip_image010

Objets crées par Spring

clip_image012

Confirmation du nombre d’appel à getConnection() : dans ce cas 10 fois moins d’appel à la connexion à la base de données que d’appel à la méthode update (qui contient la requête SQL SQL)

clip_image014

Conclusion

Pour améliorer les performances lors de la réalisation d’un grand nombre de mises à jour d'une base de données, il est fortement recommandé d’exploiter la capacité de JDBC à réaliser des mises à jour par lot.

0 commentaires :

Enregistrer un commentaire

Architecte SOA & Professionnel Open Source Headline Animator

 
Khaled BEN DRISS
Cloud Computing, SOA et Web 2.0 : Des sujets techniques sur SOA et l'Open Source : de Java & .Net, PHP5, Symfony, à SaaS / PaaS en passant par Azure, google appengine, le BPM, la Modélisation et d'autres sujets du coté du serveur et cloud computing.