sql >> Databasteknik >  >> RDS >> PostgreSQL

SQL LIMIT vs. JDBC Statement setMaxRows. Vilken är bättre?

SQL-nivå LIMIT

För att begränsa storleken på SQL-frågeresultatuppsättningen kan du använda SQL:008-syntaxen:

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

som fungerar på Oracle 12, SQL Server 2012 eller PostgreSQL 8.4 eller nyare versioner.

För MySQL kan du använda klausulerna LIMIT och OFFSET:

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

Fördelen med att använda paginering på SQL-nivå är att databasexekveringsplanen kan använda denna information.

Så, om vi har ett index på created_on kolumn:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

Och vi kör följande fråga som använder LIMIT klausul:

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

Vi kan se att databasmotorn använder indexet eftersom optimeraren vet att endast 50 poster ska hämtas:

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 Statement maxRows

Enligt setMaxRows Javadoc :

Det är inte särskilt betryggande!

Så, om vi kör följande fråga på 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++;
    }
}

Vi får följande exekveringsplan i PostgreSQL-loggen:

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 

Eftersom databasoptimeraren inte har någon aning om att vi bara behöver hämta 50 poster, antar den att alla 5000 rader måste skannas. Om en fråga behöver hämta ett stort antal poster är kostnaden för en heltabellsgenomsökning faktiskt lägre än om ett index används, därför kommer exekveringsplanen inte att använda indexet alls.

Slutsats

Även om det ser ut som setMaxRows är en bärbar lösning för att begränsa storleken på ResultSet , är sideringen på SQL-nivå mycket effektivare om databasserveroptimeraren inte använder JDBC maxRows egendom.



  1. Bästa sättet att kontrollera om det finns tomt eller nullvärde

  2. många-till-många-relation i doktrin

  3. Hur man ser den faktiska Oracle SQL-satsen som körs

  4. Skickar in kommaavgränsade värden till WHERE-satsen i Oracles lagrade procedur