PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

SQL LIMIT vs. Instrução JDBC setMaxRows. Qual é o melhor?

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.