PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

SQL LIMIT срещу JDBC оператор setMaxRows. Кой е по-добър?

ОГРАНИЧЕНИЕ на SQL ниво

За да ограничите размера на набора от резултати от SQL заявката, можете да използвате синтаксиса SQL:008:

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

който работи на Oracle 12, SQL Server 2012 или PostgreSQL 8.4 или по-нови версии.

За MySQL можете да използвате клаузите LIMIT и OFFSET:

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

Предимството на използването на пагинация на ниво SQL е, че планът за изпълнение на базата данни може да използва тази информация.

Така че, ако имаме индекс на created_on колона:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

И ние изпълняваме следната заявка, която използва LIMIT клауза:

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

Можем да видим, че машината на базата данни използва индекса, тъй като оптимизаторът знае, че трябва да бъдат извлечени само 50 записа:

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 израз maxRows

Според setMaxRows Javadoc :

Това не е много успокояващо!

И така, ако изпълним следната заявка на 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++;
    }
}

Получаваме следния план за изпълнение в регистрационния файл на PostgreSQL:

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 

Тъй като оптимизаторът на базата данни няма представа, че трябва да извлечем само 50 записа, той приема, че всичките 5000 реда трябва да бъдат сканирани. Ако една заявка трябва да извлече голям брой записи, цената на сканиране на пълна таблица всъщност е по-ниска, отколкото ако се използва индекс, следователно планът за изпълнение изобщо няма да използва индекса.

Заключение

Въпреки че изглежда като setMaxRows е преносимо решение за ограничаване на размера на ResultSet , странирането на ниво SQL е много по-ефективно, ако оптимизаторът на сървъра на база данни не използва JDBC maxRows собственост.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да разграничим име на променлива plpgsql в клауза ON CONFLICT?

  2. Гладко генериране на код само за една схема

  3. java.math.BigInteger не може да бъде прехвърлен към java.lang.Integer

  4. Разбиране на JDBC пакетни операции

  5. Задайте обща стойност на месеца на всеки ден от месеца