Implémentations de la base de données de ORDER BY dans une sous-requête

10

J'utilise une application (MapServer - http://mapserver.org/ ) qui encapsule les instructions SQL, de sorte que l'instruction ORDER BY se trouve dans la requête interne. Par exemple

SELECT * FROM (
        SELECT ID, GEOM, Name
        FROM t
        ORDER BY Name
        ) as tbl

L'application dispose de nombreux pilotes de base de données différents. J'utilise principalement le pilote MS SQL Server et SQL Server 2008. Cela génère une erreur si un ORDER BY est trouvé dans une sous-requête.

À partir de MS Docs (bien que ce soit pour SQL Server 2000, il semble toujours s'appliquer):

Lorsque vous utilisez une clause ORDER BY dans une vue, une fonction en ligne, une table dérivée ou une sous-requête, cela ne garantit pas la sortie ordonnée. Au lieu de cela, la clause ORDER BY est uniquement utilisée pour garantir que l'ensemble de résultats généré par l'opérateur Top a une composition cohérente. La clause ORDER BY garantit uniquement un jeu de résultats ordonné lorsqu'il est spécifié dans l'instruction SELECT la plus externe.

Cependant, le même type de requête lorsqu'il est exécuté dans Postgres (9) et Oracle renvoie des résultats - avec l'ordre défini dans la sous-requête. Dans Postgres, le plan de requête montre que les résultats sont triés et les notes de publication de Postgres incluent l'élément, ce qui implique que des ordres de sous-requête sont utilisés:

Évitez le tri lorsque la sous-requête ORDER BY correspond à la requête supérieure

http://en.wikipedia.org/wiki/Order_by déclare:

Bien que certains systèmes de base de données autorisent la spécification d'une clause ORDER BY dans les sous-sélections ou les définitions de vue, la présence n'a aucun effet.

Cependant, d'après ma propre vérification des plans de requête:

  • SQL Server 2008 ne prend pas en charge ORDER BY dans une sous-requête
  • Postgres 9 prend en charge ORDER BY dans une sous-requête
  • Oracle 10g prend en charge ORDER BY dans une sous-requête

Donc, ma question existe-t-il des liens qui peuvent officiellement confirmer ou nier que Postgres et Oracle n'autorisent pas le tri dans une sous-requête?

geographika
la source
2
Ce n'est pas parce que vous observez certains résultats qu'ils sont garantis. Si vous voulez de la cohérence, mettez la commande à l'extérieur. Période.
Aaron Bertrand
Idéalement, c'est ce qui sera mis en œuvre. Cependant, pour arriver à ce stade, il faudra modifier la logique principale et de nombreux pilotes de base de données. Comme ce problème n'a pas été signalé depuis de nombreuses années, il semble que certains dbs implémentent systématiquement ORDER BY dans les sous-requêtes. Ce serait bien de savoir lesquels si possible.
geographika
2
@geographika Même si certains SGBD le font de manière cohérente jusqu'à présent, rien ne garantit qu'ils continueront à faire de même à l'avenir. Par exemple, les améliorations de MySQL de l'optimiseur dans 5.6 (et MariaDB 5.3) identifieraient le ORDER BYdans la sous-requête comme redondant et ne feraient pas le tri inutile.
ypercubeᵀᴹ

Réponses:

15

Vous allez devoir faire en sorte que votre application ne mette pas l' ORDER BYintérieur de la sous-requête (peut-être qu'elle a une option pour ne pas utiliser une sous-requête inutile en premier lieu). Comme vous l'avez déjà découvert, cette syntaxe n'est pas prise en charge dans SQL Server sans TOP. Et avec TOP, à moins que vous ne vouliez laisser des lignes de côté, l'utilisation TOP 100 PERCENTva de toute façon rendre le rendu ORDER BYoptimisé.

Et dans Oracle et PostGres, ce n'est pas parce que la syntaxe est prise en charge qu'elle est respectée. Et le simple fait que vous l'observiez comme étant obéi dans certains scénarios ne signifie pas qu'il continuera à être obéi à mesure que de nouvelles versions sortent ou avec des modifications subtiles de vos données, statistiques, la requête elle-même ou l'environnement.

Je peux vous assurer que, sans aucun doute , si vous voulez une garantie sur la commande, vous devez mettre le ORDER BYsur la requête la plus externe. Cela devrait être une doctrine que vous gardez proche, quelle que soit la plateforme que vous utilisez.

Vous demandez un lien indiquant officiellement que quelque chose n'est pas pris en charge. C'est comme regarder dans le manuel du propriétaire de votre voiture pour une déclaration officielle que votre voiture ne peut pas voler.

Aaron Bertrand
la source
Merci. Je pense que MSSQL a la bonne approche pour lancer une erreur. La prise en charge et l'implémentation du tri sur les requêtes internes, quand cela va à l'encontre d'un principe SQL de base, semble une recette pour un désastre. Je ne suis pas sûr de l'analogie avec la voiture - vous devez ajouter la recherche dans le manuel pendant que la voiture vole réellement.
geographika
-1

J'admets que c'est louche mais si vous êtes pressé, essayez de renvoyer le nombre supérieur de lignes dans la sous-requête. Le retour des 100% supérieurs ne fonctionne pas, mais si vous voulez passer par la difficulté, vous pouvez interroger le nombre de lignes et le transmettre à TOP en tant que variable. J'ai testé cela sur une base de données définie au niveau de compatibilité 80, donc je pense que cela devrait fonctionner avec SQL 2000.

SELECT * FROM (
        SELECT TOP (100000) ID, GEOM, Name
        FROM t
        ORDER BY Name
        ) as tbl
DBNull
la source
J'ai essayé cela à l'origine et il semblait bien trier pour les petits ensembles de données. Cependant, lorsque j'obtenais de très grands jeux d'enregistrements, le tri est redevenu aléatoire dans SQL Server 2008R2. Peut-être concerne la taille de la mémoire / page?
geographika
Désolé, cela n'a pas aidé. La sélection des 100% supérieurs a également provoqué le tri aléatoire.
DBNull
Cela ne fonctionnera pas si la requête va en parallèle, surtout si elle Namen'est pas unique. Il peut ne pas continuer à fonctionner en série si l'optimiseur choisit un index différent, avec un ordre de colonne de clé différent.
Erik Darling