LIMIET op SQL-niveau
Om de grootte van de SQL-queryresultatenset te beperken, kunt u de SQL:008-syntaxis gebruiken:
SELECT title
FROM post
ORDER BY created_on DESC
OFFSET 50 ROWS
FETCH NEXT 50 ROWS ONLY
die werkt op Oracle 12, SQL Server 2012 of PostgreSQL 8.4 of nieuwere versies.
Voor MySQL kunt u de LIMIT- en OFFSET-clausules gebruiken:
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
OFFSET 50
Het voordeel van het gebruik van paginering op SQL-niveau is dat het uitvoeringsplan van de database deze informatie kan gebruiken.
Dus, als we een index hebben op de created_on
kolom:
CREATE INDEX idx_post_created_on ON post (created_on DESC)
En we voeren de volgende query uit die de LIMIT
. gebruikt clausule:
EXPLAIN ANALYZE
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
We kunnen zien dat de database-engine de index gebruikt, aangezien de optimizer weet dat er slechts 50 records moeten worden opgehaald:
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
JDBC-verklaring maxRows
Volgens de setMaxRows
Javadoc
:
Dat is niet erg geruststellend!
Dus, als we de volgende query uitvoeren op 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++;
}
}
We krijgen het volgende uitvoeringsplan in het PostgreSQL-logboek:
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
Omdat de database-optimizer geen idee heeft dat we slechts 50 records hoeven op te halen, gaat hij ervan uit dat alle 5000 rijen moeten worden gescand. Als een query een groot aantal records moet ophalen, zijn de kosten van een volledige-tabelscan eigenlijk lager dan wanneer een index wordt gebruikt, en daarom zal het uitvoeringsplan de index helemaal niet gebruiken.
Conclusie
Hoewel het lijkt op de setMaxRows
is een draagbare oplossing om de grootte van de ResultSet
. te beperken , is de paginering op SQL-niveau veel efficiënter als de databaseserver-optimizer de JDBC maxRows
niet gebruikt eigendom.