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

SQL LIMIT vs. JDBC Statement setMaxRows. Hvilken er bedst?

SQL-niveau LIMIT

For at begrænse størrelsen på SQL-forespørgselsresultatsættet kan du bruge SQL:008-syntaksen:

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

som virker på Oracle 12, SQL Server 2012 eller PostgreSQL 8.4 eller nyere versioner.

For MySQL kan du bruge LIMIT og OFFSET klausulerne:

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

Fordelen ved at bruge paginering på SQL-niveau er, at databaseudførelsesplanen kan bruge disse oplysninger.

Så hvis vi har et indeks på created_on kolonne:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

Og vi udfører følgende forespørgsel, der bruger LIMIT klausul:

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

Vi kan se, at databasemotoren bruger indekset, da optimizeren ved, at der kun skal hentes 50 poster:

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

Ifølge setMaxRows Javadoc :

Det er ikke særlig betryggende!

Så hvis vi udfører følgende forespørgsel 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ølgende eksekveringsplan 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 

Fordi databaseoptimeringsværktøjet ikke aner, at vi kun skal hente 50 poster, antager den, at alle 5000 rækker skal scannes. Hvis en forespørgsel skal hente et stort antal poster, er omkostningerne ved en fuld-tabel-scanning faktisk lavere, end hvis der bruges et indeks, og derfor vil udførelsesplanen slet ikke bruge indekset.

Konklusion

Selvom det ligner setMaxRows er en bærbar løsning til at begrænse størrelsen af ​​ResultSet , er pagineringen på SQL-niveau meget mere effektiv, hvis databaseserveroptimeringsværktøjet ikke bruger JDBC maxRows ejendom.



  1. readyStatement-indstillingen null for NUMBER_ARRAY virker ikke

  2. Yii2:Konvertering af en rå forespørgsel til ActiveRecord

  3. Find dublerede strenge i databasen

  4. Postgres tips og tricks