conectar - mysql-connector-java-5.1.31-bin.jar descargar
La forma más rápida de iterar a través de una tabla grande usando JDBC (3)
Estoy tratando de crear un programa Java para limpiar y fusionar filas en mi tabla. La tabla es grande, alrededor de 500k filas y mi solución actual se ejecuta muy lentamente. Lo primero que quiero hacer es simplemente obtener una matriz en memoria de objetos que representen todas las filas de mi tabla. Esto es lo que estoy haciendo:
- elija un incremento de, digamos, 1000 filas a la vez
- use JDBC para buscar un conjunto de resultados en la siguiente consulta SQL SELECCIONE * FROM TABLE WHERE ID> 0 AND ID <1000
- agregue los datos resultantes a una matriz en memoria
- continúe consultando todo el camino hasta 500,000 en incrementos de 1000, cada vez agregando resultados.
Esto está tomando mucho tiempo. De hecho, ni siquiera está pasando el segundo incremento de 1000 a 2000. La consulta tarda una eternidad en finalizar (aunque cuando ejecuto lo mismo directamente a través de un navegador MySQL es bastante rápido). Ha pasado un tiempo desde que he usado JDBC directamente. ¿Hay una alternativa más rápida?
Aunque probablemente no sea óptimo, su solución parece que debería estar bien para una rutina única de limpieza de la base de datos. No debería tomar tanto tiempo ejecutar una consulta como esa y obtener los resultados (estoy asumiendo que, dado que es uno dentro de unos segundos, estaría bien). Posibles problemas -
¿tu red (o al menos tu conexión a mysql) es muy lenta? Podría intentar ejecutar el proceso localmente en el cuadro mysql si es así, o algo mejor conectado.
¿Hay algo en la estructura de la tabla que lo está causando? tirando hacia abajo 10k de datos para cada fila? 200 campos? ¿Cómo calcular los valores de id para obtener en base a una fila no indexada? Podría tratar de encontrar una forma más fácil de utilizar los datos (por ejemplo, solo las columnas que necesita, tener los valores agregados de db, etc.etc).
Si no está superando el segundo incremento, algo está realmente mal, sea eficiente o no, no debería tener ningún problema al descargar 2000 o 20,000 filas en la memoria en una JVM en ejecución. ¿Tal vez está almacenando los datos de forma redundante o extremadamente ineficiente?
Una cosa que me ayudó fue Statement.setFetchSize(Integer.MIN_VALUE)
. Tengo esta idea del blog de Jason . Esto redujo el tiempo de ejecución en más de la mitad. La memoria consumida se redujo drásticamente (ya que solo se lee una fila a la vez).
Sin embargo, este truco no funciona para PreparedStatement
.
Antes que nada, ¿estás seguro de que necesitas toda la mesa en la memoria? Quizás debería considerar (si es posible) seleccionar las filas que desea actualizar / fusionar / etc. Si realmente tiene que tener toda la tabla, podría considerar usar un ResultSet desplazable. Puedes crearlo así
// make sure autocommit is off (postgres)
con.setAutoCommit(false);
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, //or ResultSet.TYPE_FORWARD_ONLY
ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery("select * from ...");
Le permite moverse a cualquier fila que desee mediante el uso de métodos "absolutos" y "relativos".