Procesando gran cantidad de datos desde PostgreSQL

Estoy buscando una manera de procesar una gran cantidad de datos que se cargan desde la base de datos en un tiempo razonable.

El problema que enfrento es que tengo que leer todos los datos de la base de datos (actualmente alrededor de 30 millones de filas) y luego procesarlos en Java. El procesamiento en sí no es el problema, pero sí lo es buscar datos de la base de datos. La recuperación generalmente toma de 1 a 2 minutos. Sin embargo, necesito que sea mucho más rápido que eso. Estoy cargando los datos de db directamente a DTO usando la siguiente consulta:

select id, id_post, id_comment, col_a, col_b from post_comment

Donde ides la clave primaria id_posty id_commentson claves foráneas para las tablas respectivas col_ay col_bson columnas de tipos de datos int pequeños Las columnas con claves foráneas tienen índices. Las herramientas que estoy usando para el trabajo actualmente son Java, Spring Boot, Hibernate y PostgreSQL.

Hasta ahora, las únicas opciones que se me ocurrieron fueron

  1. Olvídese de la hibernación para esta consulta e intente utilizar una conexión jdbc simple con la esperanza de que sea más rápida.
  2. Reescriba completamente el algoritmo de procesamiento de Java a procedimiento SQL.

¿Me perdí algo o estas son mis únicas opciones? Estoy abierto a cualquier idea. Tenga en cuenta que solo necesito leer los datos, no cambiarlos de ninguna manera.

EDITAR: el análisis de explicación de la consulta utilizada

"Seq Scan on post_comment (cost=0.00..397818.16 rows=21809216 width=28) (actual time=0.044..6287.066 rows=21812469 loops=1), Planning Time: 0.124 ms, Execution Time: 8237.090 ms"
Respuesta 1

¿Necesita procesar todas las filas a la vez, o puede procesarlas una a la vez?

Si puede procesarlos uno a la vez, debe intentar usar un conjunto de resultados desplazable.

org.hibernate.Query query = ...;
query.setReadOnly(true);
ScrollableResults sr = query.scroll(ScrollMode.FORWARD_ONLY);

while(sr.next())
{
    MyClass myObject = (MyClass)sr.get()[0];
    ... process row for myObject ... 
}

Esto aún recordará cada objeto en el administrador de la entidad, por lo que será cada vez más lento. Para evitar ese problema, puede separar el objeto del administrador de la entidad una vez que haya terminado. Esto solo se puede hacer si los objetos no se modifican. Si se modifican, los cambios NO serán persistentes.

org.hibernate.Query query = ...;
query.setReadOnly(true);
ScrollableResults sr = query.scroll(ScrollMode.FORWARD_ONLY);

while(sr.next())
{
    MyClass myObject = (MyClass)sr.get()[0];
    ... process row for myObject ... 
    entityManager.detach(myObject);
}
Respuesta: 2

Si estuviera en su lugar, definitivamente pasaría por alto la hibernación e iría directamente a JDBC para esta consulta. Hibernate no está hecho para lidiar con grandes conjuntos de resultados, y representa una sobrecarga adicional para beneficios que no son aplicables en casos como este.

Cuando use JDBC, no olvide establecer la confirmación automática en falso y establecer un tamaño de recuperación grande (del orden de miles) o de lo contrario, postgres recuperará primero los 21 millones de filas en la memoria antes de comenzar a cederlas. (Ver https://stackoverflow.com/a/10959288/773113)

Respuesta: 3

Dado que solicitó ideas, he visto que este problema se resuelve en las siguientes opciones según cómo se ajuste a su entorno: 1) Primero intente con JDBC y Java, código simple y puede hacer una prueba en su base de datos y datos para ver si esta mejora es suficiente Deberá comprometerse aquí con los otros beneficios de Hibernate. 2) En el punto 1, use Multi-threading con múltiples conexiones que extraen datos a una cola y luego puede usar esa cola para procesar más o imprimir según lo necesite. También puedes considerar Kafka. 3) Si los datos van a seguir aumentando, puede considerar Spark como la última tecnología que puede guardarlo todo en la memoria y será mucho más rápido.

Estas son algunas de las opciones, por favor, si estas ideas lo ayudan en alguna parte.

Respuesta: 4

Hasta el lanzamiento reciente de la nueva implementación de Java / Kotlin para Actions on Google (com.google.actions: actions-on-google: 1.0.2 Maven coordenadas), hemos estado (con éxito) utilizando su biblioteca de pares (com ...

Tengo la tabla CREATE TABLE test_wopk (número entero id, carácter "nombre" (25), número entero de edad) Después de la ingeniería inversa en hibernación, obtengo un archivo de clases y mapeo. TestWopk.java package gen; // ...

Estoy tratando de resolver el problema de 8 rompecabezas usando la búsqueda heurística. Estoy usando una matriz 3 * 3 para representar una posibilidad. El código no está completo, pero cuando intento agregar el elemento explorado al ...

Tengo una aplicación cliente-servidor, en el lado del cliente tengo un botón para recibir un marco con una tabla dentro del servidor. Si paso el marco con otros jComponents (JButton, JTextField) funciona ...