PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

SQL LIMIT a instrukcja JDBC setMaxRows. Który jest lepszy?

LIMIT na poziomie SQL

Aby ograniczyć rozmiar zestawu wyników zapytania SQL, możesz użyć składni SQL:008:

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

który działa na Oracle 12, SQL Server 2012 lub PostgreSQL 8.4 lub nowszych wersjach.

W przypadku MySQL możesz użyć klauzul LIMIT i OFFSET:

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

Zaletą korzystania z paginacji na poziomie SQL jest to, że plan wykonania bazy danych może wykorzystywać te informacje.

Tak więc, jeśli mamy indeks na created_on kolumna:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

I wykonujemy następujące zapytanie, które używa LIMIT klauzula:

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

Widzimy, że silnik bazy danych używa indeksu, ponieważ optymalizator wie, że należy pobrać tylko 50 rekordów:

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

Maksymalne wiersze instrukcji JDBC

Według setMaxRows Dokumentacja Java :

To niezbyt uspokajające!

Tak więc, jeśli wykonamy następujące zapytanie na 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++;
    }
}

W logu PostgreSQL otrzymujemy następujący plan wykonania:

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 

Ponieważ optymalizator bazy danych nie ma pojęcia, że ​​musimy pobrać tylko 50 rekordów, zakłada, że ​​należy przeskanować wszystkie 5000 wierszy. Jeśli zapytanie wymaga pobrania dużej liczby rekordów, koszt skanowania całej tabeli jest w rzeczywistości niższy niż w przypadku użycia indeksu, dlatego plan wykonania w ogóle nie będzie korzystał z indeksu.

Wniosek

Chociaż wygląda jak setMaxRows to przenośne rozwiązanie ograniczające rozmiar ResultSet , stronicowanie na poziomie SQL jest znacznie bardziej wydajne, jeśli optymalizator serwera bazy danych nie używa maxRows JDBC właściwość.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. postgres tylko przy użyciu posortowanego indeksu do odpytywania tabeli rekordów 5m

  2. Napraw „BŁĄD:każde zapytanie Z WYJĄTKIEM musi mieć taką samą liczbę kolumn” w PostgreSQL

  3. Zapomniałem hasła administratora w Postgres (instalacja Windows), nie można zresetować

  4. Zmiana klucza podstawowego na złożony klucz podstawowy

  5. HikariCP - połączenie nie jest dostępne