Pourquoi ORDER BY n'appartient-il pas à une vue?

51

Je comprends que vous ne pouvez pas avoir ORDER BY dans une vue. (Au moins dans SQL Server 2012, je travaille avec)

Je comprends également que la manière "correcte" de trier une vue consiste à placer une déclaration ORDER BYautour de la SELECTrequête.

Mais étant relativement nouveau au SQL pratique et aux usages des vues, je voudrais comprendre pourquoi cela est fait par la conception. Si j'ai bien suivi l'historique, cela était autrefois possible et a été explicitement supprimé de SQL Server 2008, etc. (ne me citez pas sur la version exacte).

Cependant, la meilleure raison pour laquelle Microsoft peut supprimer cette fonctionnalité est "une vue est une collection non triée de données".

Je suppose qu'il existe une bonne raison logique pour laquelle une vue devrait être non triée. Pourquoi une vue ne peut-elle pas être simplement une collection de données aplatie? Pourquoi spécifiquement non trié? Il ne semble pas si difficile de trouver des situations dans lesquelles (du moins pour moi / IMHO) il semble parfaitement intuitif d’avoir une vue triée.

ngmiceli
la source
2
La première réponse est parfaite. Si vous souhaitez commander une vue, je vous suggère de ne pas le faire. Sélectionnez [Colonnes] dans [YourView] Trié par [Colonnes]
Zane
Réponse courte: "Pour la même raison que ORDER BY n'appartient pas à une table."
Ypercubeᵀᴹ

Réponses:

38

(Vues indexées de côté, bien sûr.)

Une vue n'est pas matérialisée - les données ne sont pas stockées, alors comment pourrait-on les trier? Une vue est un peu comme une procédure stockée qui contient simplement un SELECTsans paramètre ... elle ne contient pas de données, elle ne contient que la définition de la requête. Etant donné que différentes références à la vue peuvent nécessiter des données triées de différentes manières, vous procédez ainsi - comme pour une sélection dans une table, qui correspond également à une collection non rangée de lignes - consiste à inclure la commande by dans la requête externe. .

Également pour donner un petit aperçu de l'histoire. Vous ne pourriez jamais mettre ORDER BYen vue, sans aussi inclure TOP. Et dans ce cas, il a été ORDER BYdicté quelles lignes étaient incluses par TOP, pas comment elles seraient présentées. Il se trouve que dans SQL Server 2000, si TOPétait 100 PERCENTou {some number >= number of rows in the table}, l’optimiseur était assez simpliste et il a fini par produire un plan avec une sorte qui correspond à la TOP/ORDER BY. Mais ce comportement n'a jamais été garanti ni documenté - il a simplement été basé sur l'observation, ce qui est une mauvaise habitude . Lorsque SQL Server 2005 est sorti, ce problème a commencé à se "rompre" en raison de changements dans l'optimiseur qui ont conduit à l'utilisation de plans et d'opérateurs différents - entre autres choses, leTOP / ORDER BYserait complètement ignoré si c'était le cas TOP 100 PERCENT. Certains clients se sont plaints de cela si fort que Microsoft a émis un indicateur de trace pour rétablir l'ancien comportement. Je ne vais pas vous dire ce qu'est le drapeau car je ne veux pas que vous l'utilisiez et je veux m'assurer que l'intention est correcte - si vous voulez un ordre de tri prévisible, utilisez- ORDER BYle dans la requête externe.

Pour résumer et clarifier tout autant ce que vous avez dit: Microsoft n’a rien supprimé . Ils ont amélioré le produit et, par conséquence, ce comportement non documenté et non garanti est devenu moins fiable. Globalement, je pense que le produit est meilleur pour cela.

Aaron Bertrand
la source
Voici comment (dans un commentaire) que le TOPcurseur effectue une opération sur le jeu de résultats. Par conséquent, il peut avoir un ordre explicite.
Tim Schmelter
@ TimSchmelter qui n'aide pas lorsque l'optimiseur le voit TOP 100 PERCENT / ORDER BYet le supprime complètement du plan. Essaye le.
Aaron Bertrand
C'était juste un sidenote. Quoi qu'il en soit, le reste du commentaire est le suivant: "L’astuce de SELECT TOP x sera obsolète dans une future version de SQL Server, il est donc préférable de ne pas l'utiliser du tout."
Tim Schmelter
@ TimSchmelter c'est déjà un no-op. Je ne pense pas que cela cessera de fonctionner dans une nouvelle version dans un avenir rapproché, car cela cassera trop de code existant.
Aaron Bertrand
2
@TimSchmelter il ordre ne parle pas de l'ordre des lignes, il parle de l'ordre des colonnes dans une ligne. Dans SQL Server, nous ne parlons généralement pas d'une ligne comme étant un tuple car l'implémentation physique d'une ligne nous est si évidente (le tableau répertorie les colonnes dans l'ordre dans lequel vous les avez définies).
Aaron Bertrand
9

Si une vue pouvait être triée alors quel devrait être l'ordre du résultat ici?

CREATE VIEW dbo.V1
AS
  SELECT number
  FROM   SomeTable
  ORDER  BY number ASC

GO

CREATE VIEW dbo.V2
AS
  SELECT number
  FROM   SomeTable
  ORDER  BY number DESC

GO

SELECT *
FROM   dbo.V1
       JOIN dbo.V2
         ON V1.number = V2.number 
Martin Smith
la source
Je ne comprends pas ce point. Au lieu d'écrire en vue de base de données, vous pouvez écrire une requête SQL normale. Alors, quel devrait être l'ordre du résultat dans ce cas? merci
Hqt
7

Une possibilité consiste à éviter les tris en conflit: si la vue trie selon un ordre et que la sélection de cette vue trie selon un autre ordre (sans tenir compte du tri de la vue), il peut y avoir un impact négatif sur les performances. Il est donc plus sûr de laisser l’exigence de tri à l’utilisateur.

Autre raison, le tri entraîne un coût en termes de performances. Pourquoi pénaliser tous les utilisateurs de la vue alors que seuls certains utilisateurs en ont besoin?

srini.venigalla
la source
5

ANSI SQL n'autorise la ORDER BYrequête la plus externe que pour une variété de raisons, l'une d'entre elles étant ce qui se produit lorsqu'une sous-sélection / vue / CTE est jointe à une autre table et que la requête externe est ORDER BYelle-même.

Le serveur SQL ne l'a jamais supporté dans une vue (à moins que vous l'ayez trompée en utilisant un TOP 100 PERCENTqui, à mon avis, provoque généralement un bogue).

Même si vous avez déclenché le bogue, les résultats n'ont jamais été fiables et le tri ne s'est pas toujours déroulé comme prévu.

Consultez ce billet de blog de l'équipe Query Optimizer pour une explication technique complète. TOP 100 pour cent ORDER BY Considered Harmful.

L'implémentation par défaut du plan pour ce code arrive à trier les lignes dans le cadre de l'exécution de l'opération TOP. Cela signifiait souvent que les résultats étaient renvoyés par ordre de tri, ce qui laissait penser aux clients qu’il y avait une garantie que les rangées étaient triées. Ce n'est en fait pas le cas. Si vous souhaitez que les lignes soient renvoyées à l'utilisateur dans l'ordre trié, vous devez utiliser un ORDER BY sur le bloc de requête le plus externe (par ANSI) pour garantir l'ordre de présentation en sortie.

Tom V
la source
3

Les vues se comportent comme des tables dont le contenu est déterminé par les résultats d'une requête.

Les tables n'ont pas d'ordre; ce ne sont que des sacs de rangées.

Par conséquent, les vues ne sont pas en ordre non plus. Vous pouvez cependant les trier en sélectionnant des lignes dans un ORDER particulier.

crépuscule
la source
1
Les tables ... ne sont que des sacs de lignes - et alors viwes ne sont que des sacs virtuels de lignes - les vues "n'existent pas" - par exemple, il n'y a pas de données stockées pour elles - elles sont juste "des définitions stockées d'une requête être exécuté ", fondamentalement.
Marc_s
1
+1 L'équivalence des tabels et des vues me semble être la principale raison pour laquelle les vues ne doivent pas contenir "d'ordre par"
miracle173
1
"Les vues se comportent comme des tables" . Je dirais que "Les vues se comportent comme des tables de base. Les vues sont des tables."
Ypercubeᵀᴹ
-2

Une réponse qui n’a pas encore été donnée est que "ordre par" peut interférer avec la poussée des prédicats, ce qui peut grandement affecter les performances.

Un exemple est d'avoir une vue qui regroupe un grand ensemble de données dans un résumé de 10 lignes qui est top 10 / Ordered:

select * from TopOrderedView; -- Ordered 10 line summary in 5s

Pour le même cas avec un prédicat fort:

select * from TopOrderedView where <condition>; -- Ordered 2 line summary in still 5s

Cela prend toujours le même temps car top / order by empêche le prédicat d'être exécuté plus tôt dans le pipeline. Cela peut entraîner le traitement de lignes inutiles et le plan sera similaire à celui sans prédicat.

Si le push doit avoir lieu avant la commande par est vraiment un choix de développeur et peut changer la réponse. Le plus souvent, le push est l'intention logique.

L'utilisation logique de "100% supérieurs" permet logiquement de pousser les prédicats, mais l'implémentation ignore malheureusement "ordre par" pour ce cas et annule l'intention.

Pour les cas d'utilisation réels, un bon compromis serait que le moteur effectue "l'ordre en tirant". Cela permettrait de spécifier un "ordre de" dans la vue (avec 100% ou aucun sommet) et cet ordre n'est utilisé que si la vue est sélectionnée directement, sans ordre explicite, sans jointure, sans agrégat, sans voir chaînage, etc. Les deux cas énumérés ci-dessus pourraient être pris en charge par ce modèle simple.

crokusek
la source
-6

vous pouvez créer une vue qui a ordre et conserve l'ordre lorsqu'il est interrogé après:

sélectionnez en haut 99,999999999999 pour cent * de ..... trier par

NasF1
la source
1
Pourquoi pas juste SELECT TOP 100 PERCENT ...?
Max Vernon
2
@ Max probablement semblable à cette astuce - cela n'en fait pas une bonne idée.
Aaron Bertrand
D'accord, @AaronBertrand - il suffit de noter qu'il n'est pas nécessaire d'utiliser 99,99999999999 :-)
Max Vernon