una seleccionar filas fila dinamicamente datos como agregar addrow java sql jdbc out-of-memory

java - seleccionar - agregar filas jtable dinamicamente



cómo cargo 100 millones de filas en la memoria (3)

Tengo la necesidad de cargar 100 millones + filas de una base de datos MySQL en la memoria. Mi programa java falla con java.lang.OutOfMemoryError: Java heap space Tengo 8GB de RAM en mi máquina y he dado -Xmx6144m en mis opciones de JVM.

Este es mi código

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()) {

¿Alguna idea de cómo superar este problema?

ACTUALIZAR

Me encontré con esta publicación , y en base a los comentarios a continuación, actualicé mi código. Parece que puedo cargar los datos en la memoria con la misma cantidad de -Xmx6144m, pero lleva mucho tiempo.

Aquí está mi código.

... 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; }

Para cargar las primeras 100,000 filas, tomó 2 segundos. Para cargar 29th 100,000 filas, tomó 46 segundos. Dejé el proceso en el medio ya que tomaba demasiado tiempo. ¿Son estas cantidades de tiempo aceptables? ¿Hay alguna forma de mejorar el rendimiento de este código? Estoy ejecutando esto en la máquina de Windows 8bit RAM de 64 bits.


El problema es que obtengo el java.lang.OutOfMemoryError en el s.executeQuery (línea en sí mismo

Puede dividir su consulta en múltiples:

s.executeQuery("SELECT movie_id,customer_id,rating FROM ratings LIMIT 0,300"); //shows the first 300 results //process this first result s.executeQuery("SELECT movie_id,customer_id,rating FROM ratings LIMIT 300,600");//shows 300 results starting from the 300th one //process this second result //etc

Puedes hacer un tiempo que se detiene cuando no se encuentran más resultados


Un centenar de millones de registros significa que cada registro puede ocupar un máximo de 50 bytes para caber dentro de los 6 GB + algún espacio adicional para otras asignaciones. En Java 50 bytes no es nada; un simple Object[] toma 32 bytes por elemento. Debe encontrar una forma de utilizar inmediatamente los resultados en su while (rs.next()) y no retenerlos por completo.


Puede llamar a stmt.setFetchSize(50); y conn.setAutoCommitMode(false); para evitar leer todo el ResultSet en la memoria.

Esto es lo que dice el documento:

Obtener resultados basados ​​en un cursor

De forma predeterminada, el controlador recopila todos los resultados de la consulta a la vez. Esto puede ser inconveniente para grandes conjuntos de datos, por lo que el controlador JDBC proporciona un medio para basar un ResultSet en un cursor de base de datos y solo recuperar un pequeño número de filas.

Se almacena en caché un pequeño número de filas en el lado del cliente de la conexión y cuando se agota se recupera el siguiente bloque de filas reposicionando el cursor.

Nota:

  • Los ResultSets basados ​​en el cursor no se pueden usar en todas las situaciones. Hay una serie de restricciones que harán que el controlador vuelva silenciosamente a buscar todo el ResultSet a la vez.
  • La conexión al servidor debe estar utilizando el protocolo V3. Este es el valor predeterminado para (y solo es compatible con) las versiones del servidor 7.4 y posteriores.-
  • La conexión no debe estar en el modo de confirmación automática. El servidor cierra los cursores al final de las transacciones, por lo que en el modo de confirmación automática el servidor habrá cerrado el cursor antes de que se pueda obtener algo de él.
  • El extracto se debe crear con un tipo ResultSet.TYPE_FORWARD_ONLY de ResultSet.TYPE_FORWARD_ONLY . Este es el valor predeterminado, por lo que no será necesario reescribir ningún código para aprovechar esto, pero también significa que no puede desplazarse hacia atrás o saltar en el ResultSet.
  • La consulta dada debe ser una sola declaración, no múltiples instrucciones unidas con punto y coma.

Ejemplo : configuración del size búsqueda para activar y desactivar los cursores.

Cambiar el código al modo cursor es tan simple como establecer el tamaño de búsqueda del Statement al tamaño apropiado. Volver a establecer el tamaño de recuperación en 0 hará que todas las filas se guarden en caché (el comportamiento predeterminado).

Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?useCursorFetch=true&user=root"); // make sure autocommit is off conn.setAutoCommit(false); Statement st = conn.createStatement(); // Turn use of the cursor on. st.setFetchSize(50); ResultSet rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("a row was returned."); } rs.close(); // Turn the cursor off. st.setFetchSize(0); rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("many rows were returned."); } rs.close(); // Close the statement. st.close();