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à.