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 :

OutOfMemoryError lors d'un select sur une grande table


Sujet :

JDBC Java

  1. #1
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut OutOfMemoryError lors d'un select sur une grande table
    Salut,

    Je dois récupérer les données d'une table qui contient plusieurs centaines de milliers de lignes afin de générer des rapports.

    Le problème c'est que j'obtiens systématiquement des OutOfMemoryError.

    Comment traîter ce problème ?

    J'ai essayé ça mais ça ne change rien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    PreparedStatement statement = connection.prepareStatement( query, ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY );
    statement.setFetchSize( 1000 );
    ResultSet resultSet = statement.executeQuery();
    Merci d'avance
    Lilian

  2. #2
    in
    in est déconnecté
    Membre expérimenté Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Points : 1 718
    Points
    1 718
    Par défaut
    à mon avis le problème mémoire ne vient pas de la requete mais du stockage des résultats ...

    tu as mis un paramètre relatif à la mémoire pour le lancement (xms, xmx ?). Dans le cas contraire la mémoire utilisée pas java est 64 Mo je crois, donc si tu peux en mettre plus ...
    "If email had been around before the telephone was invented, people would have said, 'Hey, forget email! With this new telephone invention I can actually talk to people!"

    Besoin d'une nouvelle méthode pour développer ? -> http://www.la-rache.com/

  3. #3
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par in
    à mon avis le problème mémoire ne vient pas de la requete mais du stockage des résultats ...

    tu as mis un paramètre relatif à la mémoire pour le lancement (xms, xmx ?). Dans le cas contraire la mémoire utilisée pas java est 64 Mo je crois, donc si tu peux en mettre plus ...
    Merci pour ta réponse,

    Effectivement ça vient du stockage en mémoire du résultat du select. En tout cas c'est mon impression.

    Mais je doute que la solution soit d'augmenter la mémoire alloué à la VM car cette mémoire n'est pas infinie alors que le nombre de lignes de ma table...

    Il me faudrait une vraie solution, je pourrais faire de la pagination en ajoutant des LIMIT et OFFSET à ma requête mais je préfèrerais éviter, je me dis que ça doit être une problématique classique et qu'il doit y avoir des solutions...

  4. #4
    in
    in est déconnecté
    Membre expérimenté Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Points : 1 718
    Points
    1 718
    Par défaut
    a mon avis si tu veux vraiment stocker "plusieurs centaines de milliers de lignes" en mémoire, il va falloir l'augmenter. Ya rien de choquant.

    Ensuite comment stockes tu ces données (arbre, liste ordonnée ....) ça peut jouer pas mal. Ainsi que ce que représente une ligne ... si t'as des blob et des gros textes, c'est pas gagné.

    Si tu ne veux pas augmenter la mémoire, tu n'as pas d'autre solution que de traiter morceaux par morceaux.

    Y'a pas d'autre solution je pense. Et pour moi c'est une "vraie" solution
    Qu'est ce que ce serait pour toi une "vraie" solution ?
    "If email had been around before the telephone was invented, people would have said, 'Hey, forget email! With this new telephone invention I can actually talk to people!"

    Besoin d'une nouvelle méthode pour développer ? -> http://www.la-rache.com/

  5. #5
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Je ne souhaite pas particulièrement les stocker en mémoire, j'ai juste besoin de pouvoir faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    statement.executeQuery()
    puis des

    etc.

    Avec ça je génère des PDF que j'écris sur le disque, je ne devrais pas avoir à tout stocker.

    Mais je ne sais pas comment c'est implémenté dans java.sql, donc je ne sais pas si tout le résultat de la requête est stocké ou si les données sont récupérées au fur et à mesure que j'avance mon curseur avec next().

    Je suis en train d'essayer en paginant en ajoutant des LIMIT et OFFSET à ma requête mais j'ai l'impression que je ne devrais pas avoir à faire ça

  6. #6
    in
    in est déconnecté
    Membre expérimenté Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Points : 1 718
    Points
    1 718
    Par défaut
    Citation Envoyé par lr
    Mais je ne sais pas comment c'est implémenté dans java.sql, donc je ne sais pas si tout le résultat de la requête est stocké ou si les données sont récupérées au fur et à mesure que j'avance mon curseur avec next().
    en fait tout n'est pas rapatrié d'un coup. Tu as une fetchsize qui est définie. Elle indique le nombre de lignes rapatriées par le ResultSet. Lors de l'appel à next sur la dernière ligne, il te rapatrie les suivantes. Tu peux essayer de le baisser pour voir si c'est mieux, ça va réduire la taille de l'objet ResultSet en mémoire.

    Ton problème de mémoire vient peut être de la création du fichier pdf ? as tu essayer d'utiliser un outil de profilage pour suivre l'évolution de la conso mémoire ?
    "If email had been around before the telephone was invented, people would have said, 'Hey, forget email! With this new telephone invention I can actually talk to people!"

    Besoin d'une nouvelle méthode pour développer ? -> http://www.la-rache.com/

  7. #7
    Rédacteur
    Avatar de CyberChouan
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    2 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 752
    Points : 4 314
    Points
    4 314
    Par défaut
    Est ce qu'effectuer ta requête par parties pourrait résoudre ton problème? (je ne sais pas ce que tu fais de tes données derrière ta requête)

    Dans ce cas, tu devrais peut-être exécuter ta requête par morceaux pour ne garder que 100 (ou 1000) résultats à la fois: dans ce cas, c'est sur le mot-clé LIMIT de ta requête SQL que tu dois te renseigner

    EDIT: Oups, je n'avais pas vu que tu étudiais déjà cette solution.

    Pour moi, il n'y a rien de choquant à effectuer une grosse requête en plusieurs parties en utilisant LIMIT si on ne peut pas tout traiter d'un coup
    Avant de poster, pensez à regarder la FAQ, les tutoriaux, la Javadoc (de la JRE que vous utilisez) et à faire une recherche
    Je ne réponds pas aux questions techniques par MP: les forums sont faits pour ça
    Mes articles et tutoriaux & Mon blog informatique

  8. #8
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Effectivement aucun souci à traiter par partie ... En revanche, utiliser un LIMIT, bof bof question portabilité de base .. Lui préférer les size Java... Mais apparemment tu as essayé et ça ne fonctionnait pas ?

  9. #9
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Je ne comprend vraiment pas pourquoi ce code me donne une OutOfMemoryError.

    Comme vous l'avez dit, si le nombre de lignes est très important, tout n'est pas retiré en une fois, mais au fur et à mesure des resultset.next() donc je ne comprend pas... Une mauvaise implémentation du driver jdbc peut-être ???

    Pour info il s'agit de postgresql-8.1-407.jdbc3.jar

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
     
    import com.dotbase.jasper.configuration.Configuration;
     
     
    public class TestQuery
    {
    	static Connection jdbcConnection = null;
     
    	public static void main( String args[] ) throws Exception
    	{
    		Class.forName( Configuration.getParameter("database.driver") );
    		jdbcConnection = DriverManager.getConnection("jdbc:postgresql://dbserver:5432/dbName", "username", "password");
     
     
    		String query = "Select * from t_tiers";
     
    		PreparedStatement statement = jdbcConnection.prepareStatement( query );
    		statement.setFetchSize( 100 );
    		ResultSet rsReportData = statement.executeQuery();
    	}
    }

  10. #10
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Exact à vérifier (recherche sur ce forum car déjà vu ça) mais il me semble que le driver postgres ne supporte pas les fetch size ....

  11. #11
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par chtig
    Exact à vérifier (recherche sur ce forum car déjà vu ça) mais il me semble que le driver postgres ne supporte pas les fetch size ....
    Et donc il récupérerait tout en mémoire ? Pas terrible...

    Je continue à chercher.

  12. #12
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Avec ce code ça semble marcher (piste trouvée sur http://jdbc.postgresql.org/documenta...ry-with-cursor) :

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
     
    import com.dotbase.jasper.configuration.Configuration;
     
     
    public class TestQuery
    {
    	static Connection jdbcConnection = null;
     
    	public static void main( String args[] ) throws Exception
    	{
    		Class.forName( Configuration.getParameter("database.driver") );
    		jdbcConnection = DriverManager.getConnection("jdbc:postgresql://dbserver:5432/dbname", "username", "password");
     
    		String query = "Select * from t_tiers";		
     
     
     
    		jdbcConnection.setAutoCommit( false );
     
     
    		PreparedStatement statement = jdbcConnection.prepareStatement( query );//, ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY );
    		statement.setFetchSize( 100 );
    		ResultSet rsReportData = statement.executeQuery();
    	}
    }

  13. #13
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    En fait ça marche sur les PreparedStatement et pas sur les Statement ?

  14. #14
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par chtig
    En fait ça marche sur les PreparedStatement et pas sur les Statement ?
    Il faudrait vérifier. Moi je seulement eu a ajouter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    jdbcConnection.setAutoCommit( false );
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    statement.setFetchSize( 100 );

  15. #15
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Ah ben non j'avais mal lu mais dès le début tu utilisais un Prepared. Le setFetchSize aussi ...
    Donc la seule chose que tu as changée c'est le autocommit ???

  16. #16
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par chtig
    Ah ben non j'avais mal lu mais dès le début tu utilisais un Prepared. Le setFetchSize aussi ...
    Donc la seule chose que tu as changée c'est le autocommit ???
    Oui, et j'ai lancé le code avec et sans le autocommit et c'est clair que c'est ça.

  17. #17
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Alors faudrait qu'on m'explique, parce que je ne vois pas du tout le rapport... Pour moi c'est clairement un bug du driver non ?

  18. #18
    lr
    lr est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2003
    Messages : 338
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par chtig
    Alors faudrait qu'on m'explique, parce que je ne vois pas du tout le rapport... Pour moi c'est clairement un bug du driver non ?
    Je ne suis pas suffisamment expert pour l'affirmer, mais c'est également ce que je pense

Discussions similaires

  1. Multiple SELECT sur une même TABLE
    Par anto2b dans le forum Langage SQL
    Réponses: 1
    Dernier message: 04/08/2012, 10h24
  2. Delete sur une grande table
    Par lordMehdi dans le forum Requêtes
    Réponses: 4
    Dernier message: 02/04/2012, 16h59
  3. Accès pour SELECT sur une seule table
    Par jgfa9 dans le forum Administration
    Réponses: 2
    Dernier message: 02/09/2009, 18h52
  4. Optimisation d'une requête SELECT sur une grosse table
    Par eracius dans le forum Requêtes
    Réponses: 4
    Dernier message: 26/05/2008, 14h51
  5. pb d'insertion avec un SELECT sur une autre table
    Par epeichette dans le forum Requêtes
    Réponses: 3
    Dernier message: 03/01/2005, 22h58

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