Comment lire toutes les lignes de table immense?
J'ai un problème avec le traitement de toutes les lignes à partir de la base de données (PostgreSQL). J'obtiens une erreur: org.postgresql.util.PSQLException: Ran out of memory retrieving query results.
je pense que j'ai besoin de lire toutes les lignes en petits morceaux, mais elle ne fonctionne pas - il ne lit qu'100 lignes (code ci-dessous). Comment faire?
int i = 0;
Statement s = connection.createStatement();
s.setMaxRows(100); //bacause of: org.postgresql.util.PSQLException: Ran out of memory retrieving query results.
ResultSet rs = s.executeQuery("select * from " + tabName);
for (;;) {
while (rs.next()) {
i++;
//do something...
}
if ((s.getMoreResults() == false) && (s.getUpdateCount() == -1)) {
break;
}
}
Vous devez vous connecter pour publier un commentaire.
Utilisation un CURSEUR dans PostgreSQL ou laissez JDBC pilote de gérer cela pour vous.
LIMIT et OFFSET obtiendra lente lors de la manipulation de jeux de données volumineux.
La version courte est, appel
stmt.setFetchSize(50);
etconn.setAutoCommit(false);
pour éviter de lire l'intégralité de l'ResultSet
en mémoire.Voici ce que le docs dire:
Exemple 5.2. Réglage de la taille de l'extraction de tourner les curseurs sur et en dehors.
Changeant le code de mode curseur est aussi simple que le réglage de la taille de l'extraction de la Déclaration à la taille appropriée. Réglage de la taille de l'extraction à 0, toutes les lignes de la mise en cache (le comportement par défaut).
Il s'avère donc que le noeud du problème est que par défaut, Postgres commence dans "autoCommit" de mode, et aussi il a besoin de/utilise les curseurs pour être en mesure de "page" par le biais de données (ex: lire le premier 10K résultats, puis la suivante, puis la suivante), cependant les curseurs ne peut exister qu'au sein d'une transaction. Donc la valeur par défaut est de lire toutes les lignes, toujours, dans la RAM, et puis laissez votre programme pour lancer le traitement "la première ligne, puis la deuxième" après qu'il ait tous arrivé, pour deux raisons, il n'est pas dans une transaction (afin de curseurs ne fonctionnent pas), et aussi une taille d'extraction n'a pas été définie.
Alors, comment les
psql
outil de ligne de commande atteint par lot réponse (sonFETCH_COUNT
réglage) pour les requêtes, est de "wrap" de ses requêtes de sélection au sein d'opérations à court terme (si une transaction n'est pas encore ouverte), de sorte que les curseurs peuvent travailler. Vous pouvez faire quelque chose comme ça aussi avec JDBC:Cela donne l'avantage de nécessiter moins de RAM, et, dans mes résultats, semblait courir ensemble plus rapidement, même si vous n'avez pas besoin pour économiser de la RAM. Bizarre. Il donne également l'avantage que votre traitement de première ligne "démarre plus vite" (puisque le processus d'une page à la fois).
Et voici comment le faire de la "raw postgres curseur" ainsi, le long avec plein de démonstration code, bien que dans mes expériences, il semblait JDBC façon, ci-dessus, a été légèrement plus rapide pour quelque raison que ce soit.
Une autre option serait d'avoir
autoCommit
mode off, partout, si vous avez encore de toujours spécifier manuellement un fetchSize pour chaque nouvelle Déclaration (ou vous pouvez définir une valeur par défaut taille de l'extraction dans la chaîne d'URL).Je pense que votre question est similaire à ce fil: JDBC de la Pagination qui contient des solutions adaptées à votre besoin.
En particulier, pour PostgreSQL, vous pouvez utiliser le LIMITER et COMPENSER les mots clés de votre demande: http://www.petefreitag.com/item/451.cfm
PS: Dans du code Java, je vous suggère d'utiliser PreparedStatement au lieu de simples Déclarations: http://download.oracle.com/javase/tutorial/jdbc/basics/prepared.html
Je l'ai fait comme ci-dessous. Pas le meilleur moyen je pense, mais ça fonctionne 🙂
Au moins dans mon cas, le problème était sur le client qui tente d'extraire les résultats.
Voulait obtenir .csv avec TOUS les résultats.
J'ai trouvé la solution en utilisant
(où dbname le nom de la db...) et de la rediriger vers un fichier.