sql >> Databáze >  >> RDS >> PostgreSQL

SQL LIMIT vs. příkaz JDBC setMaxRows. Který je lepší?

LIMIT na úrovni SQL

Chcete-li omezit velikost sady výsledků dotazu SQL, můžete použít syntaxi SQL:008:

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

který funguje na Oracle 12, SQL Server 2012 nebo PostgreSQL 8.4 nebo novějších verzích.

Pro MySQL můžete použít klauzule LIMIT a OFFSET:

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

Výhodou použití stránkování na úrovni SQL je, že plán provádění databáze může tyto informace využít.

Pokud tedy máme index na created_on sloupec:

CREATE INDEX idx_post_created_on ON post (created_on DESC)

A provedeme následující dotaz, který používá LIMIT klauzule:

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

Vidíme, že databázový stroj používá index, protože optimalizátor ví, že je třeba načíst pouze 50 záznamů:

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

Výkaz JDBC maxRows

Podle setMaxRows Javadoc :

To není příliš uklidňující!

Pokud tedy provedeme následující dotaz 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++;
    }
}

V protokolu PostgreSQL získáme následující plán provádění:

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 

Protože optimalizátor databáze netuší, že potřebujeme načíst pouze 50 záznamů, předpokládá, že je potřeba naskenovat všech 5000 řádků. Pokud dotaz potřebuje načíst velké množství záznamů, jsou náklady na prohledání celé tabulky ve skutečnosti nižší než při použití indexu, a proto plán provádění nebude index vůbec používat.

Závěr

I když to vypadá jako setMaxRows je přenosné řešení pro omezení velikosti ResultSet , stránkování na úrovni SQL je mnohem efektivnější, pokud optimalizátor databázového serveru nepoužívá JDBC maxRows vlastnost.



  1. Jak zobrazit znaky UTF-8 v phpMyAdmin?

  2. Oracle developer VM s Oracle 11g

  3. UTF-8:zobrazuje se správně v databázi, ale ne v HTML navzdory znakové sadě utf-8

  4. jak zkrátím vstupní e-mailovou adresu tak, aby do databáze byla vložena pouze data před @?