LIMITE de nível SQL
Para restringir o tamanho do conjunto de resultados da consulta SQL, você pode usar a sintaxe SQL:008:
SELECT title
FROM post
ORDER BY created_on DESC
OFFSET 50 ROWS
FETCH NEXT 50 ROWS ONLY
que funciona no Oracle 12, SQL Server 2012 ou PostgreSQL 8.4 ou versões mais recentes.
Para MySQL, você pode usar as cláusulas LIMIT e OFFSET:
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
OFFSET 50
A vantagem de usar a paginação em nível SQL é que o plano de execução do banco de dados pode usar essas informações.
Então, se tivermos um índice no
created_on
coluna:CREATE INDEX idx_post_created_on ON post (created_on DESC)
E executamos a seguinte consulta que usa o
LIMIT
cláusula:EXPLAIN ANALYZE
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
Podemos ver que o mecanismo de banco de dados usa o índice, pois o otimizador sabe que apenas 50 registros devem ser buscados:
Execution plan:
Limit (cost=0.28..25.35 rows=50 width=564)
(actual time=0.038..0.051 rows=50 loops=1)
-> Index Scan using idx_post_created_on on post p
(cost=0.28..260.04 rows=518 width=564)
(actual time=0.037..0.049 rows=50 loops=1)
Planning time: 1.511 ms
Execution time: 0.148 ms
Instrução JDBC maxRows
De acordo com o
setMaxRows
Javadoc
:Isso não é muito reconfortante!
Então, se executarmos a seguinte consulta no PostgreSQL:
try (PreparedStatement statement = connection
.prepareStatement("""
SELECT title
FROM post
ORDER BY created_on DESC
""")
) {
statement.setMaxRows(50);
ResultSet resultSet = statement.executeQuery();
int count = 0;
while (resultSet.next()) {
String title = resultSet.getString(1);
count++;
}
}
Obtemos o seguinte plano de execução no log do PostgreSQL:
Execution plan:
Sort (cost=65.53..66.83 rows=518 width=564)
(actual time=4.339..5.473 rows=5000 loops=1)
Sort Key: created_on DESC
Sort Method: quicksort Memory: 896kB
-> Seq Scan on post p (cost=0.00..42.18 rows=518 width=564)
(actual time=0.041..1.833 rows=5000 loops=1)
Planning time: 1.840 ms
Execution time: 6.611 ms
Como o otimizador de banco de dados não tem ideia de que precisamos buscar apenas 50 registros, ele assume que todas as 5.000 linhas precisam ser verificadas. Se uma consulta precisar buscar um grande número de registros, o custo de uma varredura de tabela completa será realmente menor do que se um índice for usado, portanto, o plano de execução não usará o índice.
Conclusão
Embora pareça com o
setMaxRows
é uma solução portátil para limitar o tamanho do ResultSet
, a paginação no nível do SQL é muito mais eficiente se o otimizador do servidor de banco de dados não usar o JDBC maxRows
propriedade.