Page 1 sur 1

[Oracle] Recherche solution équivalente à LIMIT

Posté : 30 juil. 2006, 12:40
par Ryle
Bonjour,

Je bosse avec une base oracle et je cherche la meilleure solution pour gérer une pagination comme on peut le faire sous MySql avec la commande LIMIT.
J'ai essayé d'utiliser le rownum, mais celui-ci n'est pas réattribué si l'on change le ORDER BY. Du coup il faut intégrer la requête dans un SELECT pour avoir le bon rownum. Mais autre problème, impossible de spécifier dans le WHERE un rownum supérieur à 0 (il ne trouve plus aucun élément). Obligé une fois encore d'ajouter un select autour du tout.

Ma requête ressemble donc à un truc du genre :

Code : Tout sélectionner

SELECT * FROM ( SELECT rownum AS num, x.* FROM ( SELECT * FROM table ORDER BY champ ) x ) WHERE num > 10 AND num <= 20
Ceci fonctionne, mais je trouve ça un peu lourd.
Ma question est donc de savoir s'il existe une solution plus optimisée, en sql ou en php sans avoir à ramener des milliers d'enregistrements pour n'en afficher que 10 ?

Toutes idées ou suggestions sont les bienvenues :)

Posté : 30 juil. 2006, 12:56
par Cyrano
Je ne connais pas Oracle, mais ne serait-il pas envisageable de simplifier comme ceci ?

Code : Tout sélectionner

SELECT * FROM table WHERE rownum > 10 AND rownum <= 20 ORDER BY champ;
Voire même :

Code : Tout sélectionner

SELECT * FROM table WHERE rownum BETWEEN 11 AND 20 ORDER BY champ;
:?:

Posté : 30 juil. 2006, 13:40
par Ryle
Ben non, malheureusement, comme je l'expliquais plus haut, le rownum ne tiens pas compte du order by mais se base sur l'ordre dans lequel oracle trouve les données (ce qui peut changer s'il y a un index sur la table). Ils sont donc affectés aux résultats du select et sont ensuite triés comme n'importe quelle colonne... il faut donc bien passer par une requête imbriquée.

De plus tester si le rownum est supérieur a un entier positif a pour effet de retourner faux (que ce soit un supérieur ou un between). Du coup il faut stocker le résultat et réimbriquer le tout... mais côté perf, c'est pas franchement ce qu'il y a de mieux :(

Posté : 30 juil. 2006, 13:49
par Hubert Roksor
C'est la construction que j'ai toujours vu pour ce genre de requêtes, donc on peut supposer qu'il s'agit de la seule/meilleure. Je sais qu'on peut obtenir la même chose en PL/SQL (et probablement en SQL tout seul) avec FETCH FIRST mais je n'ai jamais lu que les performances étaient meilleures.

En théorie, l'optimiseur de requêtes d'Oracle est sensé choisir le meilleur plan d'exécution sur ce genre de requêtes courantes, donc je ne me ferais pas trop de soucis à ta place :]

Posté : 30 juil. 2006, 14:00
par Cyrano
Ben je vois pas trop, à moins de créer une procédure stockée spécifique et au lieu de coder une requête, tu appelles la procédure avec un paramètre de début et un de fin. :-k

Faudrait fouiller la doc pour trouver une astuce.

Posté : 31 juil. 2006, 08:02
par Ryle
J'ai également trouvé la fonction ROW_NUMBER() pour affecter un numéro unique avec une sous-requête de moins, mais c'est pas plus performant et finalement plus compliqué à écrire vu qu'il faut ajouter un champ dans mon select initial.

Je vais regarder du côté de fetch, mais au pire je me fierais à Oracle et lui laisserais gèrer ça au mieux :)

Merci à tous les deux !

Posté : 31 juil. 2006, 09:25
par zeus
Pour appuyer ce que dit Hubert, je peut t'assurer que cette requete là est très bien optimisée par Oracle.

Et ce pour la simple et unique raison que Oracle créé un arbre des optimisations et qu'il choisi TOUJOURS la solution la plus optimisée ;)

Donc : GO :lol: