Question

J'ai une requête SQL qui ressemble à ceci:

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

Essentiellement, c’est la partie ORDER BY qui ralentit les choses. Si je devais le supprimer, le coût EXPLAIN baisserait d'un ordre de grandeur (plus de 1000 fois). J'ai essayé ceci:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

Mais cela ne donne pas de bons résultats. Existe-t-il un moyen simple d’accélérer les choses? Ou devrais-je passer plus de temps avec l'outil EXPLAIN?

Était-ce utile?

La solution

ROW_NUMBER est assez inefficace dans Oracle .

Voir l'article de mon blog pour plus de détails sur les performances:

Pour votre requête spécifique, je vous recommande de le remplacer par ROWNUM et de vous assurer que l'index est utilisé:

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

Cette requête utilisera COUNT STOPKEY

Vérifiez également que la colonne n'est pas nullable ou ajoutez la condition WHERE colonne EST NON NULL .

Sinon, l'index ne peut pas être utilisé pour récupérer toutes les valeurs.

Notez que vous ne pouvez pas utiliser ROWNUM BETWEEN: start et: end sans sous-requête.

ROWNUM est toujours attribué en dernier et vérifié en dernier. C'est ainsi que ROWNUM est toujours présent dans l'ordre, sans lacunes.

Si vous utilisez ROWNUM ENTRE 10 et 20 , la première ligne qui remplit toutes les autres conditions devient un candidat pour le renvoi, affectée temporairement avec ROWNUM = 1 et échoue. test de ROWNUM ENTRE 10 ET 20 .

Ensuite, la ligne suivante sera candidate, affectée de ROWNUM = 1 et échouera, etc., de sorte que, finalement, aucune ligne ne sera renvoyée.

Ceci devrait être contourné en plaçant les ROWNUM dans la sous-requête.

Autres conseils

Cela ressemble à une requête de pagination.

De cet article ASKTOM (environ 90% vers le bas de la page):

Vous devez commander à quelque chose unique pour ces requêtes de pagination, de sorte que ROW_NUMBER soit affecté de manière déterministe aux lignes à chaque fois.

De plus, vos requêtes ne sont pas identiques, alors je ne suis pas sûr de l’avantage de comparer les coûts de l’un à l’autre.

Votre colonne ORDER BY est-elle indexée? Sinon, c'est un bon point de départ.

Une partie du problème tient à l’ampleur du champ "début" à "fin" et à l'endroit où ils vivent. Supposons que vous avez un million de lignes dans la table et que vous voulez les lignes 567,890 à 567,900, puis vous devrez vivre avec le fait qu'il faudra parcourir toute la table, trier à peu près tout cela par identifiant, et déterminez quelles lignes entrent dans cette plage.

En bref, cela représente beaucoup de travail. C'est pourquoi l'optimiseur lui confère un coût élevé.

Ce n’est pas non plus un indice qui puisse aider beaucoup. Un index donnerait l'ordre, mais au mieux, cela vous donnerait un point de départ et vous continuerez à lire jusqu'à la 567 900e entrée.

Si vous montrez 10 articles à la fois à l'utilisateur final à la fois, il peut être intéressant de saisir les 100 meilleurs éléments de la base de données, puis de diviser l'application en 100 morceaux.

Passez plus de temps avec l'outil EXPLAIN PLAN. Si vous voyez un TABLE SCAN, vous devez modifier votre requête.

Votre requête n'a aucun sens pour moi. Interroger sur un ROWID semble demander des ennuis. Il n'y a pas d'informations relationnelles dans cette requête. Est-ce la vraie question qui vous pose problème ou un exemple que vous avez inventé pour illustrer votre problème?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top