2010-01-25 7 views
6

J'ai une table oracle avec un nombre record de 99896618.Oracle & Pagination

je dois aller chercher petit morceau de données (permet de dire 100 enregistrements) pour l'afficher sur une page Web, (Dans le monde web nous l'appelons pagination). Actuellement j'utilise la requête suivante pour accomplir cela mais les utilisateurs ne sont pas satisfaits de la performance.

SELECT * FROM (select rownum rnum,f.* from findings f where rownum<90000100) 
        WHERE rnum > 90000000 

Actuellement, 1 min 22 secondes pour obtenir les résultats. Y at-il de toute façon pour le rendre meilleur. Je suis certainement ouvert à tout type de suggestions, y compris la modification de la structure de la table ou l'ajout d'index.

(Juste Pour votre information, je suis en utilisant ASP.NET comme la technologie et ADO.NET web côté serveur en tant que couche d'accès aux données et silverlight pour la présentation côté client)

Répondre

6

Votre requête devra compter les premiers 90M enregistrements pour obtenir le prochain 100, donc il n'y a guère de place à l'amélioration.

Je ne vois pas de clause ORDER BY dans votre sous-requête, mais probablement vous l'avez. Dans ce cas, vous pouvez créer un index dessus.

Et une question: vos utilisateurs cliquent-ils vraiment sur 900K pages avant de se plaindre des performances?

Mise à jour:

Si vous avez besoin de la dernière page, vous devez réécrire votre colonne ORDER BY dans l'ordre décroissant:

SELECT * 
FROM (
     SELECT rownum rnum, f.* 
     FROM findings f 
     ORDER BY 
       record_ordering_column DESC 
     ) 
WHERE rnum > 900 
     AND rownum <= 100 

et créer un index sur record_ordering_column

Notez que je mélanger rownum à partir des requêtes imbriquées pour améliorer les performances.

Voir cet article dans mon blog pour plus de détails:

+0

J'ai rendu le numéro de page facilement accessible en créant une liste déroulante de numéros de pages (juste une description simplifiée, j'ai créé un contrôle personnalisé à travers lequel ils peuvent accéder facilement aux 1000 dernières pages). Peut-être que c'est une information utile, la plupart du temps (environ 95% du temps) les utilisateurs sont intéressés par les derniers (derniers) enregistrements. – funwithcoding

1

Si vous êtes prêt à modifier la table, je suggère que vous ajoutez une colonne rownumber à la table (en utilisant un déclencheur d'insertion et une séquence pour le définir), puis vous ajoutez un index à cette colonne.

+0

Il n'existe pas d'index non cluster ou en cluster dans Oracle, ils sont simplement appelés index. –

+0

'@OMG Ponies': oui, mais il y a des clusters indexés dans' Oracle'! :) – Quassnoi

+0

@OMG Poneys: Une clé primaire est un index clusterisé dans Oracle et tous les index de clé primaire ne sont pas groupés. Vous devez parler du mot clé 'nonclustered' * qui, je le sais, n'existe pas dans Oracle. –

5

d'un de vos commentaires:

la plupart du temps (environ 95% du temps Les utilisateurs intéressés par les derniers (derniers) enregistrements

Dans ce cas, pourquoi ne pas afficher les enregistrements dans l'ordre inverse, de sorte que 95% du temps les utilisateurs s'intéressent à la page 1 plutôt qu'à la page 900 000? S'ils veulent vraiment voir "page 900 000", cela signifie qu'ils sont intéressés par des données depuis longtemps, donc leur permettre de filtrer des données par exemple. plage de dates. Juste paginer à travers 100 millions de lignes sans aucun filtrage ne sera jamais performant.

0

Avez-vous vraiment besoin de récupérer toute la rangée?Cela signifie que vous n'utilisez aucun index.

Si vous avez toujours besoin d'obtenir la ligne entière. Utilisez le schéma suivant:

SELECT * FROM findings f1 WHERE f1.rowid IN 
    (SELECT rownum rnum, row_id 
     FROM (
      SELECT f.rowid row_id 
       FROM findings f 
      ORDER BY record_ordering_column 
      ) 
    WHERE rownum > 900 
    ) 
WHERE rnum <= 100; 

Voir

Note: la subtile clause supplémentaire SELECT ainsi que l'utilisation de l'interrogation ROWID.

Si vous ajoutez un index sur la colonne record_ordering_column, la paganation utilisera l'index pour obtenir un ensemble de ROWID. Chargez ensuite uniquement les blocs contenant les lignes identifiées par leurs ROWID.

Ce sera mieux que votre requête actuelle qui sera un balayage de table complet.