sql >> Database >  >> RDS >> PostgreSQL

SQL LIMIT vs. JDBC-instructie setMaxRows. Welke is beter?

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.



  1. Databasetabelnamen met Django

  2. Wijzig het gegevenstype van een kolom in serieel

  3. MySQL Langzaam bij deelnemen. Enige manier om te versnellen

  4. Hoe gegevens uit de database te verwijderen met behulp van een keuzerondje in php?