sql >> Base de Datos >  >> RDS >> PostgreSQL

LÍMITE de SQL frente a declaración JDBC setMaxRows. ¿Cuál es mejor?

LÍMITE de nivel SQL

Para restringir el tamaño del conjunto de resultados de la consulta SQL, puede usar la sintaxis SQL:008:

SELECT title
FROM post
ORDER BY created_on DESC
OFFSET 50 ROWS
FETCH NEXT 50 ROWS ONLY

que funciona en Oracle 12, SQL Server 2012 o PostgreSQL 8.4 o versiones más recientes.

Para MySQL, puede usar las cláusulas LIMIT y OFFSET:

SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
OFFSET 50

La ventaja de usar la paginación a nivel de SQL es que el plan de ejecución de la base de datos puede usar esta información.

Entonces, si tenemos un índice en el created_on columna:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

Y ejecutamos la siguiente consulta que usa el LIMIT cláusula:

EXPLAIN ANALYZE
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50

Podemos ver que el motor de la base de datos usa el índice ya que el optimizador sabe que solo se deben recuperar 50 registros:

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

Declaración JDBC maxRows

Según el setMaxRows Javadoc :

¡Eso no es muy tranquilizador!

Entonces, si ejecutamos la siguiente consulta en 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++;
    }
}

Obtenemos el siguiente plan de ejecución en el registro de 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 

Debido a que el optimizador de la base de datos no tiene idea de que necesitamos obtener solo 50 registros, asume que se deben escanear las 5000 filas. Si una consulta necesita obtener una gran cantidad de registros, el costo de una exploración de tabla completa es menor que si se usa un índice, por lo que el plan de ejecución no usará el índice en absoluto.

Conclusión

Aunque parece el setMaxRows es una solución portátil para limitar el tamaño del ResultSet , la paginación de nivel SQL es mucho más eficiente si el optimizador del servidor de la base de datos no usa JDBC maxRows propiedad.