PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

SQL LIMIT vs instruction JDBC setMaxRows. Quel est le meilleur?

LIMITE au niveau SQL

Pour restreindre la taille de l'ensemble de résultats de la requête SQL, vous pouvez utiliser la syntaxe SQL :008 :

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

qui fonctionne sur Oracle 12, SQL Server 2012 ou PostgreSQL 8.4 ou des versions plus récentes.

Pour MySQL, vous pouvez utiliser les clauses LIMIT et OFFSET :

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

L'avantage d'utiliser la pagination au niveau SQL est que le plan d'exécution de la base de données peut utiliser ces informations.

Donc, si nous avons un index sur le created_on colonne :

CREATE INDEX idx_post_created_on ON post (created_on DESC)

Et nous exécutons la requête suivante qui utilise le LIMIT clause :

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

Nous pouvons voir que le moteur de base de données utilise l'index puisque l'optimiseur sait que seuls 50 enregistrements sont à récupérer :

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

Déclaration JDBC maxRows

Selon le setMaxRows Javadoc :

Ce n'est pas très rassurant !

Donc, si nous exécutons la requête suivante sur 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++;
    }
}

Nous obtenons le plan d'exécution suivant dans le log 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 

Étant donné que l'optimiseur de base de données n'a aucune idée que nous n'avons besoin de récupérer que 50 enregistrements, il suppose que les 5 000 lignes doivent être analysées. Si une requête doit récupérer un grand nombre d'enregistrements, le coût d'une analyse complète de la table est en fait inférieur à celui de l'utilisation d'un index. Par conséquent, le plan d'exécution n'utilisera pas du tout l'index.

Conclusion

Bien qu'il ressemble à setMaxRows est une solution portable pour limiter la taille du ResultSet , la pagination au niveau SQL est beaucoup plus efficace si l'optimiseur de serveur de base de données n'utilise pas JDBC maxRows propriété.