web-dev-qa-db-fra.com

Paging avec Oracle

Je ne connais pas aussi bien Oracle que je le souhaiterais. J'ai environ 250 000 enregistrements et je souhaite les afficher 100 par page. Actuellement, j'ai une procédure stockée qui récupère tous les quart de million d'enregistrements dans un ensemble de données à l'aide d'un adaptateur de données et d'un ensemble de données, ainsi que de la méthode dataadapter.Fill (dataset) sur les résultats du proc stocké. Si j'ai "Nombre de pages" et "Nombre d'enregistrements par page" comme valeurs entières que je peux transmettre en tant que paramètres, quel serait le meilleur moyen de récupérer cette section en particulier. Supposons que si je passe 10 en tant que numéro de page et 120 en nombre de pages, la déclaration choisie me donnerait les valeurs 1880 à 1200, ou quelque chose du genre, mes calculs sont peut-être erronés.

Je fais cela dans .NET avec C #, pensant que ce n'était pas important, si je pouvais le faire correctement du côté SQL, alors je devrais être cool.

Mise à jour: j'ai pu utiliser la suggestion de Brian et cela fonctionne très bien. J'aimerais travailler sur une optimisation, mais les pages arrivent dans 4 à 5 secondes au lieu d'une minute, et mon contrôle de pagination a été capable de très bien s'intégrer à mes nouveaux processus stockés.

86
stephenbayer

Quelque chose comme ça devrait marcher: Du blog de Frans Bouma

SELECT * FROM
(
    SELECT a.*, rownum r__
    FROM
    (
        SELECT * FROM ORDERS WHERE CustomerID LIKE 'A%'
        ORDER BY OrderDate DESC, ShippingDate DESC
    ) a
    WHERE rownum < ((pageNumber * pageSize) + 1 )
)
WHERE r__ >= (((pageNumber-1) * pageSize) + 1)
129
Brian Schmitt

Ask Tom sur la pagination et les fonctions analytiques très utiles.

Ceci est extrait de cette page:

select * from (
    select /*+ first_rows(25) */
     object_id,object_name,
     row_number() over
    (order by object_id) rn
        from all_objects)
    where rn between :n and :m
        order by rn;
125
Chobicus

Dans l’intérêt de l’exhaustivité, pour les personnes recherchant une solution plus moderne, dans Oracle 12c , de nouvelles fonctionnalités incluent une meilleure pagination et une gestion optimale.

Paging

La pagination ressemble à ceci:

SELECT *
FROM user
ORDER BY first_name
OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;

N premiers enregistrements

Obtenir les meilleurs disques ressemble à ceci:

SELECT *
FROM user
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY

Notez comment les exemples de requête ci-dessus ont ORDER BY _ clauses. Les nouvelles commandes les respectent et sont exécutées sur les données triées.

Je ne pouvais pas trouver une bonne page de référence Oracle pour FETCH ou OFFSET mais cette page présente un bon aperçu de ces nouvelles fonctionnalités.

Performance

Comme @wweicker le souligne dans les commentaires ci-dessous, les performances sont un problème avec la nouvelle syntaxe de 12c. Je n'avais pas de copie de 18c pour vérifier si Oracle l'avait améliorée depuis.

Fait intéressant, mes résultats réels ont été renvoyés un peu plus rapidement la première fois que j'ai exécuté les requêtes sur ma table (plus de 113 millions de lignes) pour la nouvelle méthode:

  • Nouvelle méthode: 0.013 secondes.
  • Ancienne méthode: 0,107 seconde.

Cependant, comme l'a mentionné @wweicker, le plan d'explication semble bien pire pour la nouvelle méthode:

  • Nouvelle méthode coûtée: 300,110
  • Méthode ancienne coûté: 30

La nouvelle syntaxe a provoqué une analyse complète de l'index de ma colonne, ce qui représentait le coût total. Il y a de fortes chances que la situation s'aggrave lorsque l'on limite les données non indexées.

Jetons un coup d'oeil lors de l'inclusion d'une colonne unique non indexée sur le jeu de données précédent:

  • Nouvelle méthode temps/coût: 189.55 secondes/998.908
  • Ancienne méthode temps/coût: 1.973 secondes/256

Résumé: à utiliser avec prudence jusqu'à ce que Oracle améliore cette gestion. Si vous avez un index sur lequel travailler, vous pouvez peut-être vous en tirer en utilisant la nouvelle méthode.

J'espère avoir bientôt une copie du 18c pour pouvoir jouer et pouvoir mettre à jour

59
JoelC

Je veux juste résumer les réponses et les commentaires. Il y a plusieurs façons de faire une pagination.

Avant Oracle 12c, il n'y avait pas de fonctionnalité OFFSET/FETCH, alors jetez un oeil à livre blanc comme suggéré par @jasonk. C'est l'article le plus complet que j'ai trouvé sur différentes méthodes avec une explication détaillée des avantages et des inconvénients. Il faudrait beaucoup de temps pour les copier-coller ici, donc je ne le ferai pas.

Il existe également un bon article de créateurs de jooq qui explique certaines mises en garde communes avec Oracle et la pagination de bases de données. blogpost de jooq

Bonne nouvelle, depuis Oracle 12c, nous avons une nouvelle fonctionnalité OFFSET/FETCH. nouvelles fonctionnalités d'OracleMagazine 12c . Veuillez vous référer à "Requêtes Top-N et Pagination"

Vous pouvez vérifier votre version Oracle en émettant la déclaration suivante.

SELECT * FROM V$VERSION
10
Vadim Kirilchuk

Essayez ce qui suit:

SELECT *
FROM
  (SELECT FIELDA,
    FIELDB,
    FIELDC,
    ROW_NUMBER() OVER (ORDER BY FIELDC) R
  FROM TABLE_NAME
  WHERE FIELDA = 10
  )
WHERE R >= 10
AND R   <= 15;

via [tecnicume]

7
Furetto