comment puis-je charger de 100 millions de lignes à la mémoire
J'ai la nécessité de chargement de 100 millions d'+ lignes à partir d'une base de données MySQL pour la mémoire. Mon programme java échoue avec java.lang.OutOfMemoryError: Java heap space
J'ai 8 go de RAM sur ma machine et j'ai donné des -Xmx6144m dans mes options JVM.
C'est mon code
public List<Record> loadTrainingDataSet() {
ArrayList<Record> records = new ArrayList<Record>();
try {
Statement s = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
s.executeQuery("SELECT movie_id,customer_id,rating FROM ratings");
ResultSet rs = s.getResultSet();
int count = 0;
while (rs.next()) {
Une idée de comment résoudre ce problème?
Mise à JOUR
Je suis tombé sur ce post, ainsi que sur la base des commentaires ci-dessous j'ai mis à jour mon code. Il semble que je suis en mesure de charger les données dans la mémoire avec la même Xmx6144m montant, mais il prend beaucoup de temps.
Voici mon code.
...
import org.apache.mahout.math.SparseMatrix;
...
@Override
public SparseMatrix loadTrainingDataSet() {
long t1 = System.currentTimeMillis();
SparseMatrix ratings = new SparseMatrix(NUM_ROWS,NUM_COLS);
int REC_START = 0;
int REC_END = 0;
try {
for (int i = 1; i <= 101; i++) {
long t11 = System.currentTimeMillis();
REC_END = 1000000 * i;
Statement s = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
s.setFetchSize(Integer.MIN_VALUE);
ResultSet rs = s.executeQuery("SELECT movie_id,customer_id,rating FROM ratings LIMIT " + REC_START + "," + REC_END);//100480507
while (rs.next()) {
int movieId = rs.getInt("movie_id");
int customerId = rs.getInt("customer_id");
byte rating = (byte) rs.getInt("rating");
ratings.set(customerId,movieId,rating);
}
long t22 = System.currentTimeMillis();
System.out.println("Round " + i + " completed " + (t22 - t11) / 1000 + " seconds");
rs.close();
s.close();
}
} catch (Exception e) {
System.err.println("Cannot connect to database server " + e);
} finally {
if (conn != null) {
try {
conn.close();
System.out.println("Database connection terminated");
} catch (Exception e) { /* ignore close errors */ }
}
}
long t2 = System.currentTimeMillis();
System.out.println(" Took " + (t2 - t1) / 1000 + " seconds");
return ratings;
}
Charge les premiers 100 000 lignes il a fallu 2 secondes. Pour charger 29 100 000 lignes il a fallu 46 secondes. J'ai arrêté le processus dans le milieu car il prenait trop de temps. Sont-elles acceptables quantités de temps? Est-il un moyen pour améliorer les performances de ce code?
Je suis en cours d'exécution ce sur 8GO de RAM 64 bits de windows de la machine.
Quel est le besoin?
Pas sûr de ce que votre objectif est, mais Vous pouvez également faire usage de lucene.apache.org/solr pour charger et vous pouvez écrire jasper etc sur le haut et il sera beaucoup plus rapide et efficace qu'une interaction directe avec la DB.
Veuillez expliquer la nécessité. Pourquoi iriez-vous au hasard?
Une ArrayList est un mauvais choix quand on travaille avec de très grands ensembles de données. Une liste de tableau initialisé avec son constructeur par défaut - infiniment pire. Mais même si vous passez à droite de la matrice de vous allez avoir des problèmes de côté toutes les données principales de la mémoire à la fois.
OriginalL'auteur ravindrab | 2013-01-26
Vous devez vous connecter pour publier un commentaire.
Une centaine de millions d'enregistrements signifie que chaque enregistrement peut prendre jusqu'à plus de 50 octets afin de s'adapter à l'intérieur de 6 GO + un peu d'espace supplémentaire pour d'autres affectations. En Java 50 octets n'est rien, un simple
Object[]
32 octets par élément. Vous devez trouver un moyen d'utiliser immédiatement les résultats dans votrewhile (rs.next())
boucle et de ne pas conserver dans leur intégralité.oui, c'est exactement la même que celle de s.getResultSet()
Si vous obtenez OOME à
executeQuery
, c'est un signe de mauvais pilote JDBC ou, pire, une mauvaise base de données: au lieu de fournir un curseur sur le jeu de résultats, il avec impatience essaie de charger l'ensemble du jeu de résultats en mémoire. La base de données que vous utilisez?Le pilote JDBC MySQL par défaut des charges de toutes les lignes dans le jeu de résultats. Vous devez spécifier
setFetchSize(Integer.MIN_VALUE)
de la faire chercher ligne par ligne.MySQL ignore toutes les valeurs de
setFetchSize
saufInteger.MIN_VALUE
, voir la notes de mise en œuvre, en vertu deResultSet
OriginalL'auteur Marko Topolnik
Vous pouvez diviser votre requête dans plusieurs:
Vous pouvez faire un tout qui s'arrête lorsque pas plus de résultats
il ne serait pas pratique, mais il peut résoudre votre OutOfMemoryError
pouvez-vous utiliser
st.setFetchSize(5000)
J'ai utilisé. Et j'ai fait en sorte d'avoir
setAutoCommit(false)
. Mais le résultat est le même.OriginalL'auteur BackSlash
Vous pouvez appeler
stmt.setFetchSize(50);
etconn.setAutoCommitMode(false);
pour éviter la lecture de l'ensemble du jeu de résultats en mémoire.Voici ce que les docs dit:
Obtenir des résultats basés sur un curseur
Par défaut, le pilote de collecte tous les résultats de la requête à la fois. Cela peut être gênant pour les grands ensembles de données de sorte que le pilote JDBC fournit un moyen de fonder un jeu de résultats sur une base de données de curseur et seulement aller chercher un petit nombre de lignes.
Un petit nombre de lignes sont mises en cache sur le côté client de la connexion et quand épuisé le prochain bloc de lignes extraites par le repositionnement du curseur.
Remarque:
certain nombre de restrictions qui fera que le pilote silencieusement tomber en arrière
pour l'extraction de l'ensemble du jeu de résultats à la fois.
la valeur par défaut (et n'est pris en charge par le serveur de versions 7.4 et
plus tard.-
les curseurs à la fin de la transaction, donc en mode autocommit, le backend
aura fermé le curseur avant que quelque chose peut être récupérée à partir d'elle.-
ResultSet.TYPE_FORWARD_ONLY
. C'est la valeur par défaut, donc pas de codebesoin d'être réécrit pour tirer parti de cette situation, mais cela signifie aussi
que vous ne pouvez pas faire défiler vers l'arrière ou autrement sauter partout dans la
ResultSet.-
enchaînés par des points-virgules.
Exemple : Réglage de chercher
size
à son tour 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).
useCursorFetch=true
est nécessaire dans l'URL de connexion pour que cette approche fonctionne.vous êtes de droite. J'ai mis à jour ma réponse. plz vérifier. laissez-moi savoir si tout autre problème. Merci
OriginalL'auteur Vipin Jain
Vous aurait à modifier et charger les données dans la mémoire en morceaux.
Exemple
1) première Charge de 1 million d'enregistrements à partir de la DB à l'aide de SQL(sql de choisir seulement 1 million de dollars) et les processus de
2) Charger sur un autre morceau.
setFetchSize ne suffiront pas à résoudre ce problème.
OriginalL'auteur Vijay Kumar Chauhan