Así que resulta que el problema es que, de manera predeterminada, Postgres se inicia en modo "autocommit", y también necesita/utiliza cursores para poder "buscar" datos (por ej .: leer los primeros 10K resultados, luego el siguiente, luego el siguiente), sin embargo, los cursores solo pueden existir dentro de una transacción. Por lo tanto, el valor predeterminado es leer todas las filas, siempre, en la RAM, y luego permitir que su programa comience a procesar "la primera fila de resultados, luego la segunda" después de que haya llegado, por dos razones, no está en una transacción (por lo que los cursores no funciona), y tampoco se ha establecido un tamaño de búsqueda.
Entonces, ¿cómo la herramienta de línea de comandos psql
logra la respuesta por lotes (su posición FETCH_COUNT
) para las consultas, es de "envolver" sus consultas de selección dentro de una transacción a corto plazo (si la operación aún no está abierto), de modo que los cursores puede trabajar. Se puede hacer algo así también con JDBC:
static void readLargeQueryInChunksJdbcWay(Connection conn, String originalQuery, int fetchCount, ConsumerWithException<ResultSet, SQLException> consumer) throws SQLException {
boolean originalAutoCommit = conn.getAutoCommit();
if (originalAutoCommit) {
conn.setAutoCommit(false); // start temp transaction
}
try (Statement statement = conn.createStatement()) {
statement.setFetchSize(fetchCount);
ResultSet rs = statement.executeQuery(originalQuery);
while (rs.next()) {
consumer.accept(rs); // or just do you work here
}
} finally {
if (originalAutoCommit) {
conn.setAutoCommit(true); // reset it, also ends (commits) temp transaction
}
}
}
@FunctionalInterface
public interface ConsumerWithException<T, E extends Exception> {
void accept(T t) throws E;
}
Esto da la ventaja de requerir menos memoria RAM, y, en mis resultados, parecía correr más rápido en general, incluso si no es necesario para salvar la memoria RAM. Extraño. También da la ventaja de que el procesamiento de la primera fila "comienza más rápido" (ya que lo procesa una página a la vez).
Y he aquí cómo hacerlo con el "cursor de postgres en bruto", junto con la demo completa code, aunque en mis experimentos parecía que el modo JDBC, arriba, era ligeramente más rápido por cualquier razón.
Otra opción sería desactivar el modo autoCommit
, en cualquier lugar, aunque todavía tiene que especificar manualmente un fetchSize para cada nuevo Statement (o puede establecer un tamaño de búsqueda predeterminado en la cadena URL).
El segundo enlace no funciona ... – snorbi
Pruebe este: http://jdbc.postgresql.org//documentation/head/query.html # fetchsize-example –