2009-10-01 10 views
8

Je suis en train d'exécuter une requête postgresql qui renvoie un grand résultat:jdbc + grande requête postgresql donnent de mémoire

connection.setAutoCommit(false); 
st = connection.createStatement(
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.TYPE_FORWARD_ONLY 
); 
st.setFetchSize(100); 
logMemory(); 
System.out.println("start query "); 
rs = st.executeQuery(queryString); 
System.out.println("done query "); 
logMemory(); 

mais utilise beaucoup de mémoire:

Free memory; 4094347680 (= 3905 mb). 
start query 
done query 
Free memory; 2051038576 (= 1956 mb). 

(imprimé avec Runtime.getRuntime(). freeMemory())

Jusqu'à présent cela fonctionne mais la base de données va être beaucoup plus grande. Je n'ai jamais besoin du résultat entier en mémoire; J'ai juste besoin de traiter chaque ligne, écrire les résultats sur le disque et aller à la rangée suivante. Je sais que 'setFetchSize' est seulement un indice, mais je trouverais étrange que postgresql/jdbc l'ignore, car il existe depuis des lustres.

Un moyen de le contourner? Ma seule idée jusqu'ici est de faire un script batch qui transmet le résultat de la requête sur le disque, puis analyser le fichier à partir de Java ...

+0

Juste curieux, quelle est la taille maximale de tas que vous utilisez? Ou utilisez-vous par défaut? –

+1

C'est -Xmx4096M -Xms4096M, c'est une machine Vista de 8 Go. – kresjer

Répondre

7

Ouch, c'est l'un des bogues les plus méchants utilisant JDBC que j'ai vu. Vous devez changer

st = connection.createStatement(
    ResultSet.CONCUR_READ_ONLY, 
    ResultSet.TYPE_FORWARD_ONLY 
); 

dans

st = connection.createStatement(
    ResultSet.TYPE_FORWARD_ONLY, 
    ResultSet.CONCUR_READ_ONLY 
); 

Peut-être simplement

st = connection.createStatement(); 

fonctionnera aussi bien (que vous avez rencontré les autres critères pour un curseur).

+0

quel est le bug? est-ce une vraie fuite de mémoire ou est-ce que quelque chose d'autre se passe? Pensez-vous que c'est postgres seulement? – rogerdpack

+0

@rogerdpack OP a modifié les paramètres de la méthode 'createStatement'. Les deux paramètres sont 'int' -s mais signifie des choses différentes. Ce n'est donc pas un bug dans l'implémentation de JDBC. –

9

Here sont les directives pour s'assurer que le jeu de résultats est réellement récupéré avec un curseur . Vous semblez atteindre tous les noms connus dans votre code, mais vous n'avez pas spécifié l'instruction, donc elle peut être plusieurs fois avec des points-virgules (peu probable, selon l'apparence de votre code). Vous devez utiliser le protocole V3 (version 7.4 ou ultérieure). Est-ce que toutes ces choses s'appliquent à votre cas?

+0

Oui, j'ai essayé d'activer/désactiver toutes les directives. L'instruction est simplement Sélectionnez hh.data, hh.customer_ID de dataTable hh joindre le client PH sur hh.customer_ID = PH.customer_ID; et c'est postgresql 8.3 et j'utilise postgresql-8.3-603.jdbc4.jar. – kresjer

+0

Je suis perplexe. Je dirais que la prochaine étape consiste à poster sur des groupes qui se concentrent sur Postgresql. Il y a probablement d'autres choses non évidentes qui provoquent/peuvent forcer la connexion à utiliser un curseur. Je vais ouvrir le code source JDBC (c'est la bonne chose à propos de l'open source) et voir ce qui se passe dans votre scénario. – Yishai

+1

Merci beaucoup pour la réponse. J'ai lutté ce problème pendant toute la journée, jusqu'à ce que j'ai trouvé une exigence pour 'conn.setAutoCommit (false)' sur la page que vous avez citée. – jutky

Questions connexes