PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

LIMITE SQL e istruzione JDBC setMaxRows. Qual è il migliore?

LIMITE a livello SQL

Per limitare la dimensione del set di risultati della query SQL, puoi utilizzare la sintassi SQL:008:

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

che funziona su Oracle 12, SQL Server 2012 o PostgreSQL 8.4 o versioni successive.

Per MySQL, puoi utilizzare le clausole LIMIT e OFFSET:

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

Il vantaggio dell'utilizzo dell'impaginazione a livello SQL è che il piano di esecuzione del database può utilizzare queste informazioni.

Quindi, se abbiamo un indice su created_on colonna:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

Ed eseguiamo la seguente query che utilizza il LIMIT clausola:

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

Possiamo vedere che il motore di database utilizza l'indice poiché l'ottimizzatore sa che devono essere recuperati solo 50 record:

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

Dichiarazione JDBC maxRows

Secondo setMaxRows Javadoc :

Non è molto rassicurante!

Quindi, se eseguiamo la seguente query su 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++;
    }
}

Otteniamo il seguente piano di esecuzione nel log di 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 

Poiché l'ottimizzatore di database non ha idea della necessità di recuperare solo 50 record, presuppone che tutte le 5000 righe debbano essere scansionate. Se una query deve recuperare un numero elevato di record, il costo di una scansione dell'intera tabella è in realtà inferiore rispetto a se viene utilizzato un indice, quindi il piano di esecuzione non utilizzerà affatto l'indice.

Conclusione

Sebbene assomigli a setMaxRows è una soluzione portatile per limitare la dimensione del ResultSet , l'impaginazione a livello SQL è molto più efficiente se l'ottimizzatore del server di database non utilizza JDBC maxRows proprietà.