Quelle est la différence entre une expression de table commune (CTE) et une table temporaire? Et quand dois-je utiliser l'un sur l'autre?
CTE
WITH cte (Column1, Column2, Column3)
AS
(
SELECT Column1, Column2, Column3
FROM SomeTable
)
SELECT * FROM cte
Tableau des températures
SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable
SELECT * FROM #tmpTable
C'est assez large, mais je vais vous donner une réponse aussi générale que possible.
CTE ...
VIEW
s# Tables Temp ...
Quant à savoir quand les utiliser, ils ont des cas d'utilisation très différents. Si vous avez un jeu de résultats très volumineux ou devez y faire référence plusieurs fois, mettez-le dans un #temp
table. S'il doit être récursif, jetable ou simplement simplifier quelque chose, un CTE
est préférable.
De plus, un CTE
devrait ne jamais être utilisé pour les performances. Vous n'accélérerez presque jamais les choses en utilisant un CTE, car, encore une fois, ce n'est qu'une vue jetable. Vous pouvez faire des choses intéressantes avec eux, mais accélérer une requête n'en fait pas vraiment partie.
MODIFIER:
Veuillez voir les commentaires de Martin ci-dessous:
Le CTE n'est pas matérialisé comme une table en mémoire. C'est juste un moyen d'encapsuler une définition de requête. Dans le cas de l'OP, il sera aligné et revient à faire simplement
SELECT Column1, Column2, Column3 FROM SomeTable
. La plupart du temps, ils ne sont pas matérialisés à l'avance, c'est pourquoi cela ne renvoie aucune ligneWITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X
, vérifiez également les plans d'exécution. Bien qu'il soit parfois possible de pirater le plan pour obtenir une bobine. Un élément de connexion demande un indice à ce sujet. - Martin Smith 15 février 12 à 17:08
Réponse originale
Un CTE crée la table utilisée en mémoire, mais n'est valide que pour la requête spécifique qui la suit. Lorsque vous utilisez la récursivité, cela peut être une structure efficace.
Vous pouvez également envisager d'utiliser une variable de table. Ceci est utilisé comme une table temporaire est utilisée et peut être utilisée plusieurs fois sans avoir besoin d'être re-matérialisée pour chaque jointure. De plus, si vous devez conserver quelques enregistrements maintenant, ajoutez quelques enregistrements supplémentaires après la sélection suivante, ajoutez quelques enregistrements supplémentaires après une autre opération, puis renvoyez uniquement cette poignée d'enregistrements, cela peut être une structure pratique, comme elle ne le fait pas. pas besoin d'être abandonné après l'exécution. Surtout juste du sucre syntaxique. Cependant, si vous maintenez le nombre de lignes bas, il ne se matérialise jamais sur le disque. Voir Quelle est la différence entre une table temporaire et une variable de table dans SQL Server? pour plus de détails.
En savoir plus sur MSDN - Faites défiler environ 40% du chemin
Une table temporaire est littéralement une table créée sur disque, juste dans une base de données spécifique dont tout le monde sait qu'elle peut être supprimée. Il est de la responsabilité d'un bon développeur de détruire ces tables lorsqu'elles ne sont plus nécessaires, mais un DBA peut également les effacer.
Les tables temporaires sont de deux types: locales et globales. En termes de MS SQL Server, vous utilisez une désignation #tableName
Pour local et une désignation ##tableName
Pour global (notez l'utilisation d'un simple ou double # comme caractéristique d'identification).
Notez qu'avec les tables temporaires, contrairement aux variables de table ou CTE, vous pouvez appliquer des index et similaires, car ce sont légitimement des tables au sens normal du mot.
En général, j'utilisais des tables temporaires pour des requêtes plus longues ou plus grandes, et des CTE ou des variables de table si j'avais déjà un petit ensemble de données et que je voulais juste rapidement écrire un peu de code pour quelque chose de petit. L'expérience et les conseils des autres indiquent que vous devez utiliser les CTE lorsque vous en avez renvoyé un petit nombre de lignes. Si vous avez un grand nombre, vous bénéficierez probablement de la possibilité d'indexer sur la table temporaire.
Le réponse acceptée dit ici "un CTE ne devrait jamais être utilisé pour la performance" - mais cela pourrait induire en erreur. Dans le contexte des CTE par rapport aux tables temporaires, je viens de terminer de supprimer une partie des fichiers indésirables d'une suite de procs stockés car certains doofus ont dû penser qu'il y avait peu ou pas de surcharge pour utiliser les tables temporaires. J'ai poussé le lot dans les CTE, sauf ceux qui allaient légitimement être réutilisés tout au long du processus. J'ai gagné environ 20% de performances pour toutes les métriques. J'ai ensuite décidé de supprimer tous les curseurs qui tentaient d'implémenter un traitement récursif. C'est là que j'ai vu le plus grand gain. J'ai fini par réduire les temps de réponse d'un facteur dix.
Les CTE et les tables temporaires ont des cas d'utilisation très différents. Je veux juste souligner que, bien que n'étant pas une panacée, la compréhension et l'utilisation correcte des CTE peuvent conduire à des améliorations vraiment stellaires à la fois en qualité/maintenabilité du code et en vitesse. Depuis que je les maîtrise, je vois les tables temporaires et les curseurs comme les grands maux du traitement SQL. Je peux me débrouiller très bien avec les variables de table et les CTE pour presque tout maintenant. Mon code est plus propre et plus rapide.
Un CTE peut être appelé à plusieurs reprises dans une requête et est évalué chaque fois qu'il est référencé - ce processus peut être récursif. S'il n'est référencé qu'une seule fois, il se comporte comme une sous-requête, bien que les CTE puissent être paramétrés.
Une table temporaire est physiquement persistante et peut être indexée. En pratique, l'optimiseur de requêtes peut également conserver les résultats de jointure ou de sous-requête intermédiaire en arrière-plan, comme dans les opérations de spoule, il n'est donc pas strictement vrai que les résultats des CTE ne soient jamais conservés sur le disque.
Les variables de table de l'IIRC (en revanche) sont toujours des structures en mémoire.
La table temporaire est un véritable objet dans tempdb, mais cte n'est qu'une sorte de wrapper autour d'une requête complexe pour simplifier la syntaxe d'organisation de la récursivité en une seule étape.
La principale raison d'utiliser des CTE est d'accéder aux fonctions de fenêtre telles que row_number()
et diverses autres.
Cela signifie que vous pouvez faire des choses comme obtenir la première ou la dernière ligne par groupe TRÈS TRÈS rapidement et efficacement - plus efficacement que d'autres moyens dans la plupart des cas pratiques .
with reallyfastcte as (
select *,
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;
Vous pouvez exécuter une requête similaire à la précédente en utilisant une sous-requête corrélée ou en utilisant une sous-requête, mais le CTE sera plus rapide dans presque tous les scénarios.
De plus, les CTE peuvent vraiment aider à simplifier votre code. Cela peut entraîner des gains de performances car vous comprenez mieux la requête et pouvez introduire davantage de logique métier pour aider l'optimiseur à être plus sélectif.
De plus, les CTE peuvent améliorer les performances si vous comprenez votre logique métier et savez quelles parties de la requête doivent être exécutées en premier - généralement, placez d'abord vos requêtes les plus sélectives qui mènent à des jeux de résultats qui peuvent utiliser un index dans leur prochaine jointure et ajoutez le option(force order)
indice de requête
Enfin, les CTE n'utilisent pas tempdb par défaut, vous réduisez donc les conflits sur ce goulot d'étranglement grâce à leur utilisation.
Des tables temporaires doivent être utilisées si vous devez interroger les données plusieurs fois, ou alternativement si vous mesurez vos requêtes et découvrez cela en l'insérant dans une table temporaire et puis en ajoutant un index que vos performances sont améliorées.
Il semble y avoir un peu de négativité ici envers les CTE.
Ma compréhension d'un CTE est qu'il s'agit essentiellement d'une sorte de vision ad hoc. SQL est à la fois un langage déclaratif et un langage basé sur un ensemble. Les CTE sont un excellent moyen de déclarer un ensemble! Ne pas pouvoir indexer un CTE est en fait une bonne chose car vous n'en avez pas besoin! C'est vraiment une sorte de sucre syntaxique pour faciliter la lecture/écriture de la requête. Tout optimiseur décent élaborera le meilleur plan d'accès en utilisant des index sur les tables sous-jacentes. Cela signifie que vous pouvez accélérer efficacement votre requête CTE en suivant les conseils d'indexation sur les tables sous-jacentes.
De plus, ce n'est pas parce que vous avez défini un ensemble comme CTE que toutes les lignes de l'ensemble doivent être traitées. En fonction de la requête, l'optimiseur peut traiter "juste assez" de lignes pour satisfaire la requête. Peut-être que vous n'aviez besoin que des 20 premiers environ pour votre écran. Si vous avez construit une table temporaire, vous devez vraiment lire/écrire toutes ces lignes!
Sur cette base, je dirais que les CTE sont une excellente fonctionnalité de SQL et peuvent être utilisés partout où ils facilitent la lecture de la requête. Je ne penserais qu'à une table temporaire pour un processus batch qui aurait vraiment besoin de traiter chaque enregistrement. Même alors, afaik n'est pas vraiment recommandé car sur une table temporaire, il est beaucoup plus difficile pour la base de données de vous aider avec la mise en cache et les index. Il pourrait être préférable d'avoir une table permanente avec un champ PK unique à votre transaction.
Je dois admettre que mon expérience concerne principalement DB2, je suppose donc que CTE fonctionne de la même manière dans les deux produits. Je me ferai un plaisir de corriger si les CTE sont en quelque sorte inférieurs dans le serveur SQL. ;)