Dans cette excellente question SO , les différences entre CTE
et sub-queries
ont été discutées.
Je voudrais demander spécifiquement:
Dans quelles circonstances chacun des éléments suivants est-il plus efficace / plus rapide?
- CTE
- Sous-requête
- Table temporaire
- Variable de table
Traditionnellement, j'en ai utilisé beaucoup temp tables
dans le développement stored procedures
- car ils semblent plus lisibles que beaucoup de sous-requêtes entrelacées.
Non-recursive CTE
s encapsulent très bien les ensembles de données et sont très lisibles, mais y a-t-il des circonstances spécifiques où l'on peut dire qu'ils fonctionneront toujours mieux? ou s'agit-il de devoir toujours tripoter les différentes options pour trouver la solution la plus efficace?
ÉDITER
On m'a récemment dit qu'en termes d'efficacité, les tables temporaires sont un bon premier choix car elles ont un histogramme associé, c'est-à-dire des statistiques.
Réponses:
SQL est un langage déclaratif, pas un langage procédural. Autrement dit, vous construisez une instruction SQL pour décrire les résultats souhaités. Vous ne dites pas au moteur SQL comment faire le travail.
En règle générale, il est judicieux de laisser le moteur SQL et l'optimiseur SQL trouver le meilleur plan de requête. Le développement d'un moteur SQL demande de nombreuses années-personnes, alors laissez les ingénieurs faire ce qu'ils savent faire.
Bien sûr, il existe des situations où le plan de requête n'est pas optimal. Ensuite, vous souhaitez utiliser des conseils de requête, restructurer la requête, mettre à jour les statistiques, utiliser des tables temporaires, ajouter des index, etc. pour obtenir de meilleures performances.
Quant à votre question. Les performances des CTE et des sous-requêtes devraient, en théorie, être les mêmes, car les deux fournissent les mêmes informations à l'optimiseur de requêtes. Une différence est qu'un CTE utilisé plus d'une fois peut être facilement identifié et calculé une fois. Les résultats pourraient ensuite être stockés et lus plusieurs fois. Malheureusement, SQL Server ne semble pas tirer parti de cette méthode d'optimisation de base (vous pourriez appeler cette élimination de sous-requête commune).
Les tables temporaires sont différentes, car vous fournissez plus de conseils sur la façon dont la requête doit être exécutée. Une différence majeure est que l'optimiseur peut utiliser les statistiques de la table temporaire pour établir son plan de requête. Cela peut entraîner des gains de performances. De plus, si vous avez un CTE (sous-requête) compliqué qui est utilisé plusieurs fois, le stockage dans une table temporaire augmentera souvent les performances. La requête n'est exécutée qu'une seule fois.
La réponse à votre question est que vous devez jouer pour obtenir les performances que vous attendez, en particulier pour les requêtes complexes qui sont exécutées régulièrement. Dans un monde idéal, l'optimiseur de requêtes trouverait le chemin d'exécution parfait. Bien qu'il le fasse souvent, vous pourrez peut-être trouver un moyen d'obtenir de meilleures performances.
la source
Il n'y a pas de règle. Je trouve les CTE plus lisibles et les utilise à moins qu'ils ne présentent un problème de performance, auquel cas j'étudie le problème réel plutôt que de deviner que le CTE est le problème et j'essaie de le réécrire en utilisant une approche différente. Le problème ne se résume généralement pas à la façon dont j'ai choisi de déclarer mes intentions de manière déclarative avec la requête.
Il y a certainement des cas où vous pouvez démêler des CTE ou supprimer des sous-requêtes et les remplacer par une table #temp et réduire la durée. Cela peut être dû à diverses choses, telles que les statistiques obsolètes, l'impossibilité même d'obtenir des statistiques précises (par exemple, se joindre à une fonction de valeur de table), le parallélisme ou même l'incapacité à générer un plan optimal en raison de la complexité de la requête ( dans ce cas, sa rupture peut donner à l'optimiseur une chance de se battre). Mais il existe également des cas où les E / S impliquées dans la création d'une table #temp peuvent l'emporter sur les autres aspects des performances qui peuvent rendre une forme de plan particulière utilisant un CTE moins attrayante.
Honnêtement, il y a beaucoup trop de variables pour fournir une réponse «correcte» à votre question. Il n'y a aucun moyen prévisible de savoir quand une requête peut pencher en faveur d'une approche ou d'une autre - sachez simplement qu'en théorie, la même sémantique pour un CTE ou une seule sous-requête devrait exécuter exactement la même chose. Je pense que votre question serait plus utile si vous présentez des cas où ce n'est pas vrai - il se peut que vous ayez découvert une limitation dans l'optimiseur (ou en ayez découvert une connue), ou il se peut que vos requêtes ne soient pas sémantiquement équivalentes ou que celui-ci contient un élément qui contrarie l'optimisation.
Je suggère donc d'écrire la requête de la manière qui vous semble la plus naturelle et de ne dévier que lorsque vous découvrez un problème de performances réel que l'optimiseur rencontre. Personnellement, je les classe en CTE, puis en sous-requête, la table #temp étant le dernier recours.
la source
link / edit / close / flag
- s'il y a eu des votes pour fermer la question, vous verrezclose (n)
oùn
représente le nombre d'utilisateurs qui ont voté pour fermer votre question. Si vous cliquez sur le lien, vous verrez les raisons pour lesquelles ces utilisateurs ont sélectionné.#temp est matérialisé et CTE ne l'est pas.
CTE est juste une syntaxe donc en théorie c'est juste une sous-requête. Il est exécuté. #temp est matérialisé. Ainsi, un CTE coûteux dans une jointure exécutée plusieurs fois peut être préférable dans un #temp. D'un autre côté, si c'est une évaluation facile qui n'est pas exécutée mais quelques fois alors ne vaut pas la surcharge de #temp.
Il y a des gens sur SO qui n'aiment pas les variables de table mais je les aime car ils sont matérialisés et plus rapides à créer que #temp. Il y a des moments où l'optimiseur de requête fait mieux avec un #temp par rapport à une variable de table.
La possibilité de créer un PK sur une variable #temp ou table donne à l'optimiseur de requête plus d'informations qu'un CTE (car vous ne pouvez pas déclarer un PK sur un CTE).
la source
Je pense que seulement 2 choses qui rendent TOUJOURS préférable d'utiliser une table # Temp plutôt qu'un CTE sont:
Vous ne pouvez pas mettre de clé primaire sur un CTE, de sorte que les données auxquelles le CTE accède devront traverser chacun des index des tables du CTE plutôt que d'accéder simplement au PK ou à l'index sur la table temporaire.
Parce que vous ne pouvez pas ajouter de contraintes, d'index et de clés primaires à un CTE, ils sont plus sujets aux bogues et aux mauvaises données.
-onjour quand hier
Voici un exemple où les contraintes #table peuvent empêcher les mauvaises données ce qui n'est pas le cas dans les CTE
la source
ALWAYS
est un peu trop loin mais merci pour la réponse. En termes de lisibilité, l'utilisation des CTE peut être une bonne chose.CHECK
contrainte faisant référence à plusieurs lignes / tables est interdit). Pouvez-vous publier un exemple où un CTE présente un bogue que l'équivalent de la table temporaire ne fait pas?