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 :

problème de Heap Space - Peut-on vider la mémoire lors du parcours d'un ResultSet ?


Sujet :

JDBC Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2014
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2014
    Messages : 16
    Par défaut problème de Heap Space - Peut-on vider la mémoire lors du parcours d'un ResultSet ?
    Bonjour à tous,

    Je dois faire une requête sur une table Oracle de 165.000.000 de lignes, l'objectif étant de mesurer le temps mis par la requête (le résultat n'est pas important et n'est bien sur pas affiché).
    Cela fonctionne si je fais un Select max(champ1) from source; car mon ResultSet ne me renvoie qu'une valeur mais je ne sais pas comment gérer une requête de type Select champ1 from source;.
    Pour que ma requête soit effective et que le SGBD parcoure la table, je fais un resultset.last(); et j'ai une erreur de type java heap space (ou garbage collector overhead limit) à partir de 2.5 millions de lignes.

    J'ai modifié les paramètres -Xms et -Xmx au niveau du fichier eclipse.ini ou dans les paramètres Java de Windows mais je suis très loin du compte.
    Je voulais donc savoir si il était possible de vider (en partie ?) la mémoire qui se remplit lors d'un ResultSet ?
    Sachant que c'est un curseur, j'ai l'impression qu'il enregistre en mémoire des informations dès que je le bouge et, dès lors, j'imagine qu'il est possible de vider cette mémoire.

    J'ai modifié la valeur du Fetch (100, 500, 1000) ce qui modifie les quantités de données que gère le driver mais cela ne résout pas mon problème.
    Souhaitant avoir le résultat exact de la requête, je ne peux pas "découper" celle-ci en plusieurs sous-requêtes (de 0 à 2 millions, de 2 à 4 millions, ...)

    Code de création du Resultset :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    PreparedStatement ps=conn.prepareStatement(request, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
    ...
    ResultSet rs = ps.executeQuery();
    ...
    rs.last();
    Merci de votre aide !
    (Je suis débutant en Java, merci de pardonner des erreurs ou des oublis de ma part)

  2. #2
    Membre Expert
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Par défaut
    Tu veux quoi précisement?
    Le temps d'exécution de la requête? Le nombre de résultats?

    Parce que techniquement, à partir du moment où tu arrives au premier rs.next, ta requête a terminé de s'exécuter.
    Donc si c'est effectivement ça, ben voilà... Tu as déjà réussi, tu n'as pas besoin de parcourir les infos pour avoir plus d'infos

    Détail cependant : les requêtes sont la plupart du temps optimisées par le SGBD, donc deux requête identiques ne donneront pas toujours le même résultat. Le seul moyen de connaitre le coût d'une requête est d'étudier son plan d'exécution

  3. #3
    Membre averti
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2014
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2014
    Messages : 16
    Par défaut
    Je m’intéresse au temps pris par la requête comme si celle-ci s'effectuait directement à partir de la base (donc complètement d'où le rs.last() )
    En fait, je génère, récupère et analyse le fichier trace d'Oracle et je récupère une valeur bien précise de celui-ci (elapsed time).
    Il me faut donc avoir la requête qui s'effectue complètement.

    Mais, je me demande si je pars de la bonne façon. Si je fais un resultset.last() il y aura 165 millions de connexions entre mon appli et la base Oracle ? et du coup le résultat du fichier Trace sera biaisé ?

    Si c'est le cas, je dois peut-être oublier JDBC ? et passer par des scripts sur la machine distante contenant la base ...

  4. #4
    Membre Expert
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Par défaut
    Citation Envoyé par baba63 Voir le message
    Je m’intéresse au temps pris par la requête comme si celle-ci s'effectuait directement à partir de la base (donc complètement d'où le rs.last() )
    Complètement pour toi, c'est le temps pris par la base pour exécuter la requête, ou le temps pour l'exécuter et parcourir l'intégralité des résultats? Avec un scrollable resultset, quand tu fais un rs.last, il se positionne sur le dernier enregistrement, normalement il ne lit pas toutes les valeurs (avec le driver Oracle du moins, MySQL renvoie tout...)

    Le elapsed time d'une requête est le temps de parcours et de création des résultats, une fois que le premier résultat arrive, la requête est considérée comme terminée quel que soit le temps que tu passes à le parcourir.

    Enlève le scrollable (TYPE_SCROLL_INSENSITIVE) qui ne te sert à rien si tu veux juste faire un last : si tu n'as que besoin d'aller à la fin sans revenir en arrière ça devrait être suffisant

  5. #5
    Membre averti
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2014
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2014
    Messages : 16
    Par défaut
    Merci de ton aide eulbobo

    " c'est le temps pris par la base pour exécuter la requête, ou le temps pour l'exécuter et parcourir l'intégralité des résultats? "
    Pour moi, c'est la même chose mais visiblement, il doit me manquer des fondamentaux sur les bases de données.
    Je voudrais simuler le comportement de la base lorsqu'un utilisateur lance une requête "select champ1 from source;"

    Lorsque je me positionne sur un enregistrement assez distant, cela prend du temps (environ 8-10 secondes pour arriver à un million d'enregistrement) que je fasse des resultset.next() jusqu'a while (rs.getRow()<1000000) ou directement rs.absolute(1000000); (à vue d’œil, le comportement semble identique)
    Je pensais qu'il lisait les valeurs mais c'est vrai que cela ne correspond pas.
    Quand je fais cette requête sur la base, je mets environ 45 minutes et 10s*165 ne font pas 45 minutes.
    Il doit y avoir un enregistrement des informations quelque part tout de même car j'ai un problème de heap space.

    "Le elapsed time d'une requête est le temps de parcours et de création des résultats, une fois que le premier résultat arrive, la requête est considérée comme terminée quel que soit le temps que tu passes à le parcourir"

    Merci pour tes explications, je me prenais la tête depuis deux jours pour parcourir la table alors que je n'en ai pas besoin.
    Un resultset.next suffira donc !

  6. #6
    Membre averti
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2014
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2014
    Messages : 16
    Par défaut
    En fait, après vérifications, si je fais juste une requête select champ from source; et que j'utilise rs.next(); au lieu de rs.last(); , j'obtiens un elapsed time de 0 alors qu'il est de 9 pour la même requête avec un rs.last() lorsque cela plante vers 2,5 millions de lignes lues.

    Après, je ne sais pas comment est construite la base, il y a peut-être un comportement spécifique.

    De toutes façons, il faudra que je récupère das le futur, d'autres résultats du fichier trace et du coup, je reviens sur la question de départ et le fonctionnement du resultset.
    Qu'est ce qui est enregistré en mémoire ? Peut-on vider cette mémoire ?
    Faut-il éviter d'utiliser JDBC pour un tel cas ?

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

Discussions similaires

  1. Java heap space Exception, problème de mémoire
    Par Bobble dans le forum Servlets/JSP
    Réponses: 11
    Dernier message: 08/11/2010, 18h04
  2. Réponses: 10
    Dernier message: 25/08/2010, 21h07
  3. Problème mémoire Java heap space avec tableau et ArrayList
    Par phoenix420 dans le forum Collection et Stream
    Réponses: 45
    Dernier message: 22/06/2010, 10h01
  4. Problème avec le Java heap space
    Par Viscapon dans le forum JSF
    Réponses: 5
    Dernier message: 18/05/2009, 17h42
  5. problème heap space
    Par selmaK dans le forum Général Java
    Réponses: 3
    Dernier message: 17/04/2007, 02h43

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