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 pour l'execution d'une requete de type SELECT


Sujet :

JDBC Java

  1. #1
    Futur Membre du Club
    Inscrit en
    Mai 2008
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 13
    Points : 7
    Points
    7
    Par défaut Problème pour l'execution d'une requete de type SELECT
    Bonjour,

    J'ai créé un programme java qui se connecte à une base de données distante. J'ai deux petits problèmes :

    - Lorsque je fais une requete du type SELECT *, le temps pour executer cette commande en java est de plus de 2min. (Qu'il y ait 1 000 ou 100 000 lignes)

    Y a t-il un moyen d'accélerer cette commande ? Quand je l'execute dans le logiciel qui gère la base de données, il faut à peine 1 seconde.

    - Lorsqu'il y a plus de 2 millions de lignes, il y a une erreur OutOfMemoryError. Un résultset n'est pas censé garder qu'un bloc de lignes en mémoire ?

    Merci

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    On pourrait voir ton code...


    a++

  3. #3
    Futur Membre du Club
    Inscrit en
    Mai 2008
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    Je mets juste la partie du code pour la connection à la base de données :

    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
     
    Class.forName("com.mysql.jdbc.Driver").newInstance();
    System.out.println("Driver charge !!");
     
    conn = DriverManager.getConnection("jdbc:mysql://ip:port/DB", "login", "mdp");
    System.out.println("Connexion etablie !!");
     
    for (int ii = 0; ii<300; ii++) {
     
                String queryString = "SELECT `Code` FROM `data` GROUP BY `Code` ORDER BY `Code` LIMIT ?,?";
     
                PreparedStatement statement = conn.prepareStatement( queryString );
                statement.setInt(1, 1000*ii);
                statement.setInt(2, 1000*ii+999);
     
                resultat = statement.executeQuery();
                System.out.println("Requete OK !!");
     
                //Traitements sur le résultat de la requete
    }
    A chaque fois que j'appelle la méthode executeQuery(), il faut environ 2 à 3 min pour passer à la suite du code.

    J'ai fait une boucle pour essayer de contourner le problème de OutOfMemory, pour ne pas charger tous les enregistrements d'un coup.

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Est-ce que tu fermes bien les différents éléments (statement, resultset) ?

    a++

  5. #5
    Futur Membre du Club
    Inscrit en
    Mai 2008
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    Merci beaucoup pour tes réponses très rapides.

    Effectivement, je viens de vérifier, je ne les fermais pas... De plus, en relisant mon message, je me suis aperçu que je triais les enregistrements à chaque fois que j'executais la requete (ORDER BY) ... Sur une base de données de plusieurs millions de lignes, ça prend tout de suite du temps... Un problème de réglé.


    Sinon maintenant, question rapidité, vaut-il mieux utiliser une boucle avec un LIMIT dans la requête, ou plutôt faire un SELECT * pour sélectionner tous les enregistrements en une seule fois ? A condition bien sur que je trouve d'où vient cette erreur de OutOfMemory ..

    Merci encore pour tes réponses !

  6. #6
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par istaccr Voir le message
    De plus, en relisant mon message, je me suis aperçu que je triais les enregistrements à chaque fois que j'executais la requete (ORDER BY) ... Sur une base de données de plusieurs millions de lignes, ça prend tout de suite du temps... Un problème de réglé.
    Si tu as un index sur le champs cela ne devrait pas être si couteux je pense...


    Citation Envoyé par istaccr Voir le message
    Sinon maintenant, question rapidité, vaut-il mieux utiliser une boucle avec un LIMIT dans la requête, ou plutôt faire un SELECT * pour sélectionner tous les enregistrements en une seule fois ?
    Si tu veux récupérer tous les éléments je ne vois pas trop l'intérêt d'utiliser une boucle avec des LIMITs...

    Citation Envoyé par istaccr Voir le message
    A condition bien sur que je trouve d'où vient cette erreur de OutOfMemory ..
    Il faudrait voir le stacktrace complet de l'exception...


    Sinon, quels traitements tu fais sur le résultat de la requete ?


    a++

  7. #7
    Futur Membre du Club
    Inscrit en
    Mai 2008
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    J'utilisais juste le LIMIT parce que sinon il y a une erreur de mémoire, et que je n'arrivais pas à trouver d'où ça provenait.

    Voici l'erreur que j'ai lorsque je charge tous mes enregistrements en une fois :

    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
     
    Exception in thread "Thread-6" java.lang.OutOfMemoryError: Java heap space
    	at java.util.Arrays.copyOf(Unknown Source)
    	at java.util.Arrays.copyOf(Unknown Source)
    	at java.util.ArrayList.ensureCapacity(Unknown Source)
    	at java.util.ArrayList.add(Unknown Source)
    	at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:2374)
    	at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:451)
    	at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:2076)
    	at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:1451)
    	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1787)
    	at com.mysql.jdbc.Connection.execSQL(Connection.java:3283)
    	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1332)
    	at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1467)
    	at FunctionResearch.Research(FunctionResearch.java:55)
    	at AppletTest$15.run(AppletTest.java:366)
    Pour chaque code, je le décompresse, puis je selectionne ceux qui sont en relation avec un code donné précédemment.

  8. #8
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Essayes peut-être de redéfinir le fetch-size avec setFetchSize()...


    Sinon cela semble venir du driver JDBC, donc tu devrais éplucher http://bugs.mysql.com/ à la recherche d'un bug similaire.

    a++

    PS : Question subsidiaire : pourquoi as-tu besoin de récupérer tous les éléments de la table ?

  9. #9
    Futur Membre du Club
    Inscrit en
    Mai 2008
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    J'ai testé setFetchSize() avec plusieurs valeurs, comme par exemple 100, 1000, 10000; mais toujours le même résultat..

    Sinon j'ai besoin de récupérer tous les résultats parce les enregistrements correspondent à un code, et dans ce code, il y a plusieurs informations que je dois comparer avec des données fournies par l'utilisateur. Je suis obligé de regarder tous les enregistrements de la base.

    Je vais regarder les bugs liés à ce driver, merci.

  10. #10
    Membre à l'essai
    Inscrit en
    Février 2003
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 14
    Points : 16
    Points
    16
    Par défaut
    istaccr, ne pourrais-tu pas extraire l'info que tu as besoin directement de la base de donnée?
    Je veux dire plutôt que de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    String queryString = "SELECT `Code` FROM `data` GROUP BY `Code` ORDER BY `Code`"; 
    PreparedStatement statement = conn.prepareStatement( queryString );
    resultat = statement.executeQuery();
     
    //traitement pour chaque resultat
    tu pourais faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    String critere = "quelquechose"
    //Je ne connais pas syntaxe exacte pour MySql  mais je suppose que je ne dois pas en être loin.
    //De plus le sql permet quand même de faire des choses un minimum complexe
    String queryString = "SELECT SUBSTR(code, 0, 5) FROM `data` GROUP BY `Code` WHERE code like '%?%'";
     
    PreparedStatement statement = conn.prepareStatement( queryString );
    statement.setString(1, critere);
    resultat = statement.executeQuery();
     
    //traitement pour les résultats directement intéressants
    Comme ça tu fait le traitement d'extraction directement dans la base de donnée et pas en java.

  11. #11
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par istaccr Voir le message
    J'ai testé setFetchSize() avec plusieurs valeurs, comme par exemple 100, 1000, 10000; mais toujours le même résultat..
    Apparemment il semble que MySQL ne gère pas cela car il ne gère pas de vrai curseur...

    Et par défaut le driver JDBC chargerait toutes les données dans la JVM, d'où ton OutOfMemory...
    http://dev.mysql.com/doc/refman/5.0/...ion-notes.html

    By default, ResultSets are completely retrieved and stored in memory. In most cases this is the most efficient way to operate, and due to the design of the MySQL network protocol is easier to implement. If you are working with ResultSets that have a large number of rows or large values, and can not allocate heap space in your JVM for the memory required, you can tell the driver to stream the results back one row at a time.
    Apparemment d'après cette page la solution serait d'utiliser les attributs ResultSet.TYPE_FORWARD_ONLY et ResultSet.CONCUR_READ_ONLY lors de la création du Statement et d'utiliser la valeur Integer.MIN_VALUE pour le fetchSize, ce qui donnerait dans ton cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    PreparedStatement statement = conn.prepareStatement( queryString, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
    statement.setFetchSize(Integer.MIN_VALUE);

    [edit] Maintenant si tu peux faire un maximum de traitement directement dans la requête SQL ce serait mieux

    a++

  12. #12
    Futur Membre du Club
    Inscrit en
    Mai 2008
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    Merci pour vos réponses.

    La solution de adiGuba fonctionne, je n'ai plus l'erreur.


    Je suis en train de tester la solution de toon, je n'avais pas vu les choses dans ce sens, mais pourquoi pas. C'est beaucoup plus rapide en temps de calculs, mais beaucoup plus difficile à mettre en place. Je vais voir si tous cas fonctionneront avec cette méthode.

    Merci encore

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

Discussions similaires

  1. Sorte de if dans une requete de type select
    Par shaun_the_sheep dans le forum Langage SQL
    Réponses: 2
    Dernier message: 27/04/2010, 17h55
  2. problème de l'execution d'une requete
    Par azräel dans le forum VB.NET
    Réponses: 12
    Dernier message: 02/06/2009, 08h21
  3. probléme execution d'une requete
    Par sarah_s dans le forum C#
    Réponses: 5
    Dernier message: 30/05/2007, 17h21
  4. Réponses: 2
    Dernier message: 10/05/2007, 17h07
  5. Réponses: 2
    Dernier message: 20/04/2006, 14h33

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