IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JDBC Java Discussion :

Performances requête SQL et parcours de ResultSet


Sujet :

JDBC Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 143
    Points : 68
    Points
    68
    Par défaut Performances requête SQL et parcours de ResultSet
    Bonjour,

    Je développe une appli web avec Spring. J'utilise l'API Spring JDBC pour l'accès à la base de données. Récemment la base de données (Oracle 11g) et le serveur d'application (Tomcat) ont été migrés dans un "Datacentre" aux Etats-Unis.
    Depuis des scripts Java ou des JUnit que je lance sur mon poste en France rament lors de l'accès aux données. Jusqu'ici rien de très surprenant, la latence réseau due à l'éloignement de la base en est la cause.
    Cependant le comportement n'est pas celui auquel je m'attendais. Je pensais qu'une requête SELECT allait prendre plus de temps à s'exécuter mais que une fois les résultats transférés sur mon PC, le parcours du ResultSet JDBC serait aussi rapide. Or ce n'est pas ce qui se passe. Je constate qu'il y a une latence à chaque appel de rs.getString(..) pour chaque ligne et itération du ResultSet. Comme si les lignes composant le ResultSet étaient transférées une à une lors de l'itération sur le ResultSet. Or je pensais que tous les résultats étaient ramenés en masse côté appli Java puis qu'on bouclait dessus avec le ResultSet.

    Quelqu'un pourrait-il me confirmer ce comportement de JDBC et m'apporter de plus amples explications ?

    Si les lignes sont bien ramenées une à une, y aurait-il un moyen avec JDBC d'exécuter une requête afin que les lignes soient ramenées en masse de façon et ne pas avoir de latence à l'intérieur de l'itération sur le ResultSet ? Je sais qu'il est possible d'avoir ce genre de comportement "batch" pour les UPDATE et les INSERT où l'on envoie par exemple 2000 insert d'un coup à la base en un seul aller-retour.

    Un exemple de code pour illustrer mon propos :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    		return jdbcTemplate.query("select * from produit", new ResultSetExtractor<List<Produit>>() {
    			@Override
    			public List<Produit> extractData(ResultSet rs) throws SQLException, DataAccessException {
    				List<Produit> produits = new ArrayList<Produit>();
    				LOGGER.debug("Commence à recevoir des résultats de la base de données");
    				while (rs.next()) {
    					Produit p = new Produit();
    					p.setId(rs.getLong("id"));// Latence à laquelle je ne m'attendais pas
    					p.setName(rs.getString("name"));// Latence à laquelle je ne m'attendais pas ... etc.
    					produits.add(p);
    				}
    				return produits;
    			}
    		});
    Donc pour reprendre, je pensais que le fait que la base de données soit très éloignées de mon PC où tourne le code allait augmenter le temps d'apparition du log "Commence à recevoir des résultats de la base de données" et c'est tout. Or il y a également de la latence sur les getters du resultSet.

    Merci d'avance pour votre aide

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 143
    Points : 68
    Points
    68
    Par défaut
    Personne n'a d'idée ?

  3. #3
    Membre expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Points : 3 083
    Points
    3 083
    Par défaut
    Salut,

    Les select JDBC fonctionnent effectivement comme tu le penses, le fetch des données se fait uniquement à chaque appel de rset.getTruc().

    Le ResultSet est un curseur pointant vers les données en base, mais il ne récupère rien de lui même.

    Il est donc normal que tu constates des latences à chaque appel (mais par contre tu as vraiment une connection pourrie avec ta base pour pouvoir constater ce phénomène.

    Tu pourrais légèrement optimiser les perfs en suivant les recommandations d'usage pour les select de base relationnelle :

    - toujours donner les noms de colonnes à récupérer explicitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select id, name from produit
    (et jamais de select *)

    - récupérer les valeurs selon leur index et non leur nom (interpréter le nom de la colonne demande un travaille supplémentaire au driver alors que donner l'index, il se pose pas de question) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int i = 1;
    p.setId(rs.getLong(i++));
    p.setId(rs.getString(i++));
    Et sinon, niveau Spring, tu pourrais faire un queryForList et utiliser un RowMapper, ça t'évitera de coder l'initialisation de list et l'ajout des lignes dedans (ça ne changera pas les perfs, c'est juste plus concis au niveau du code).

    Essaie mes 2 suggestions et donne un retour sur ce fil, ça m'intéresse de savoir si tu constates une amélioration.

    ++

  4. #4
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Mars 2009
    Messages
    54
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2009
    Messages : 54
    Points : 59
    Points
    59
    Par défaut
    j'ai lu quelque part que les PreparedStatement sont plus rapides parce qu'elles sont pré-compilées.

  5. #5
    Membre expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Points : 3 083
    Points
    3 083
    Par défaut
    Citation Envoyé par byubi Voir le message
    j'ai lu quelque part que les PreparedStatement sont plus rapides parce qu'elles sont pré-compilées.
    Aucun rapport avec ce problème, désolé. Et ce n'est pas tout à fait exact en plus sur le fond, c'est l'utilisation des bind variables qui permet l'optimisation (les ? dans ta requête) en permettant d'utiliser plusieurs fois la même requête avec des variables différentes. Et ça dépend aussi du SGBD.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 143
    Points : 68
    Points
    68
    Par défaut
    Merci natha pour ta réponse.

    Le code que j'ai fourni n'était qu'un exemple pour illustrer le fait que chaque appel à rs.getTruc(..) rame. Dans mon code réel je n'utilise effectivement jamais de "select *" et je spécifie toujours les colonnes. D'autre part j'accède toujours aux données du ResultSet par l'index pour éviter au driver sous-jacent de perdre du temps à analyser les metadata si j'accède par le nom de la colonne. Enfin lorsque je passe des paramètres à la requête, je fais un "binding" avec des "?". Cela permet effectivement de profiter du cache de Oracle. Merci donc pour ces conseils, mais je les mettais déjà en pratique.

    Cependant, n'y a-t-il pas moyen de ramener toutes ces lignes en bloc en un seul aller-retour vers la base de données ? J'imagine que non. Cela impliquerait de charger toutes les données dans une Collection Java en mémoire et l'API JDBC doit considérer que tel n'est pas le rôle du Driver JDBC. Je repose la question cependant.

    Merci

  7. #7
    Membre expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Points : 3 083
    Points
    3 083
    Par défaut
    Parfait si tu fais déjà tout juste.

    Pour être plus fin tu peux regarder ça :

    http://www.precisejava.com/javaperf/j2ee/JDBC.htm

    Il a l'air d'y avoir quelques astuces, rien de transcendant toutefois.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 143
    Points : 68
    Points
    68
    Par défaut
    Merci beaucoup natha pour ce lien ! Au contraire ça m'a l'air tout a fait transcendant ! Notamment la méthode ResultSet.setFetchSize(..) qui semble permettre de configurer le nombre de lignes ramenées en un seul aller-retour à la base.

    Je teste ça et vous tiens au courant !

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 143
    Points : 68
    Points
    68
    Par défaut
    Bonjour à tous, Bonjour natha,

    Je confirme que la méthode ResultSet.setFetchSize(..) a considérablement amélioré la performance du parcours du ResultSet. C'est exactement cette méthode que je recherchais : un moyen de ramener "en bloc" beaucoup de lignes en un seul aller-retour à la base de données.

    Merci

  10. #10
    Membre expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Points : 3 083
    Points
    3 083
    Par défaut
    Super, bon à savoir, merci du retour.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [WD17] Performance interface, requête sql trop longue, inutilisable.
    Par droliprane dans le forum WinDev
    Réponses: 28
    Dernier message: 08/09/2015, 12h04
  2. [2.x] requête sql, problème performance
    Par SuperArbre dans le forum Symfony
    Réponses: 3
    Dernier message: 14/01/2014, 08h59
  3. Performance requête SQL
    Par remdel59 dans le forum Langage SQL
    Réponses: 9
    Dernier message: 04/07/2012, 17h07
  4. performance des requêtes SQL
    Par haykelFST dans le forum Développement
    Réponses: 3
    Dernier message: 20/10/2011, 18h28
  5. [12.5.4]Problème de performances sur requête SQL
    Par tdeco dans le forum Adaptive Server Enterprise
    Réponses: 5
    Dernier message: 25/05/2010, 22h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo