web-dev-qa-db-fra.com

Meilleure pratique pour la pagination dans Oracle?

Problème: j’ai besoin d’écrire des procédures stockées qui renverront le jeu de résultats d’une seule page de lignes et le nombre total de lignes.

Solution A: Je crée deux procédures stockées, une qui renvoie un ensemble de résultats d'une page et une autre qui renvoie un scalaire - nombre total de lignes. Le plan Explain indique que le premier sproc a un coût de 9 et le second 3.

SELECT  *
FROM    ( SELECT ROW_NUMBER() OVER ( ORDER BY D.ID DESC ) AS RowNum, ...
        ) AS PageResult
WHERE   RowNum >= @from
    AND RowNum < @to
ORDER BY RowNum

SELECT  COUNT(*)
FROM    ...

Solution B: J'ai tout mis dans un seul sproc en ajoutant le même numéro TotalRows à la ligne toutes les du jeu de résultats. Cette solution a l'air malpropre, mais a un coût de 9 et un seul sproc, donc je suis enclin à utiliser cette solution.

SELECT * 
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY D.ID DESC  ) RowNum, COUNT(*) OVER () TotalRows,
WHERE RowNum >= from
        AND RowNum < to
ORDER BY RowNum;

Existe-t-il une meilleure pratique de pagination dans Oracle? Laquelle des solutions susmentionnées est la plus utilisée dans la pratique? Est-ce que l'un d'entre eux est considéré comme tout simplement faux? Notez que ma base de données est et restera relativement petite (moins de 10 Go).

J'utilise Oracle 11g et le dernier fichier ODP.NET avec VS2010 SP1 et Entity Framework 4.4. J'ai besoin de la solution finale pour fonctionner au sein de l'EF 4.4. Je suis sûr qu'il existe probablement de meilleures méthodes pour la pagination en général, mais j'ai besoin qu'elles fonctionnent avec EF.

26
Howie

Si vous utilisez déjà l'analyse (ROW_NUMBER() OVER ...), l'ajout d'une autre fonction analytique sur le même partitionnement entraînera un coût négligeable pour la requête.

Par ailleurs, il existe de nombreuses autres façons de faire la pagination, l’une d’elles utilisant rownum:

SELECT * 
  FROM (SELECT A.*, rownum rn
          FROM (SELECT *
                  FROM your_table
                 ORDER BY col) A
         WHERE rownum <= :Y)
 WHERE rn >= :X

Cette méthode sera supérieure si vous avez un index approprié sur la colonne de classement. Dans ce cas, il serait peut-être plus efficace d'utiliser deux requêtes (une pour le nombre total de lignes, une pour le résultat).

Les deux méthodes sont appropriées, mais en général, si vous souhaitez à la fois le nombre de lignes et un ensemble de pagination, l'utilisation de l'analyse est plus efficace, car vous interrogez les lignes une seule fois.

25
Vincent Malgrat

Cela peut aider:

   SELECT * FROM 
     ( SELECT deptno, ename, sal, ROW_NUMBER() OVER (ORDER BY ename) Row_Num FROM emp)
     WHERE Row_Num BETWEEN 5 and 10;
4
Art

Dans Oracle 12C, vous pouvez utiliser la limite LIMIT et OFFSET pour la pagination.

Exemple - Supposons que vous disposiez de la table tab à partir de laquelle les données doivent être extraites sur la base de la colonne de type de données DATEdt dans l'ordre décroissant à l'aide de la pagination.

page_size:=5

select * from tab
order by dt desc
OFFSET nvl(page_no-1,1)*page_size ROWS FETCH NEXT page_size ROWS ONLY;

Explication:

page_no = 1 page_size = 5

OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY - Récupère les 5 premières lignes uniquement

page_no = 2 page_size = 5

OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY - Récupère les 5 prochaines lignes 

etc.

Pages de référence - 

https://dba-presents.com/index.php/databases/Oracle/31-new-pagination-method-in-Oracle-12c-offset-fetch

https://Oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#paging

1
Tajinder

Essaye ça:

select * from ( select * from "table" order by "column" desc ) where ROWNUM > 0 and ROWNUM <= 5;
1
Carlos

J'ai également fait face à un problème similaire. J'ai essayé toutes les solutions ci-dessus et aucune ne m'a donné de meilleures performances. J'ai un tableau avec des millions d'enregistrements et j'ai besoin de les afficher à l'écran en pages de 20. J'ai procédé comme suit pour résoudre le problème.

  1. Ajoutez une nouvelle colonne ROW_NUMBER dans la table.
  2. Définissez la colonne comme clé primaire ou ajoutez-y un index unique. 
  3. Utilisez le programme Population (dans mon cas, Informatica) pour renseigner la colonne avec rownum.
  4. Récupérer des enregistrements de la table en utilisant entre les instructions. (SELECT * FROM TABLE WHERE ROW_NUMBER ENTRE LOWER_RANGE ET UPPER_RANGE). 

Cette méthode est efficace si nous devons effectuer une extraction de pagination inconditionnelle sur une table volumineuse. 

0
Ram Kiran

Désolé, celui-ci fonctionne avec le tri:

SELECT * FROM (SELECT ROWNUM rnum,a.* FROM (SELECT * FROM "tabla" order by "column" asc) a) WHERE rnum BETWEEN "firstrange" AND "lastrange";
0
Carlos