Les vues en ligne vous permettent de sélectionner dans une sous-requête comme s'il s'agissait d'une table différente:
SELECT
*
FROM /* Selecting from a query instead of table */
(
SELECT
c1
FROM
t1
WHERE
c1 > 0
) a
WHERE
a.c1 < 50;
J'ai vu que cela faisait référence à l'utilisation de différents termes: vues en ligne, clause WITH, CTE et tables dérivées. Pour moi, il semble que ce soit une syntaxe spécifique au fournisseur différente pour la même chose.
Est-ce une fausse hypothèse? Existe-t-il des différences techniques / de performances entre celles-ci?
oracle
cte
derived-tables
Kshitiz Sharma
la source
la source
WITH...
). Vous pouvez réécrire chaque table dérivée en CTE, mais peut-être pas l'inverse (par exemple, CTE récursif ou utiliser le CTE plusieurs fois)Réponses:
Il existe des différences importantes entre les vues en ligne (tables dérivées) et la clause WITH (CTE) dans Oracle. Certains d'entre eux sont assez universels, c'est-à-dire qu'ils s'appliquent à d'autres SGBDR.
WITH
peut être utilisé pour créer des sous-requêtes récursives, vue en ligne -pas (pour autant que je sache, il en va de même pour tous les SGBDR qui prennent en charge CTE)WITH
clause est plus susceptible d'être exécutée physiquement en premier; dans de nombreux cas, le choix entreWITH
et la vue en ligne permet à l'optimiseur de choisir différents plans d'exécution (je suppose que c'est spécifique au fournisseur, peut-être même à la version).WITH
peut être matérialisée sous la forme d'une table temporaire (je ne sais pas si un autre fournisseur mais Oracle prend en charge cette fonctionnalité).WITH
peut être référencée plusieurs fois, dans d'autres sous-requêtes et dans la requête principale (vrai pour la plupart des SGBDR).la source
LATERAL
est utilisée.D'autres réponses couvrent assez bien les différences de syntaxe, donc je n'entrerai pas dans les détails. Au lieu de cela, cette réponse couvrira simplement les performances dans Oracle.
L'optimiseur Oracle peut choisir de matérialiser les résultats d'un CTE dans une table temporaire interne. Il utilise une heuristique pour ce faire au lieu d'une optimisation basée sur les coûts. L'heuristique est quelque chose comme "Matérialiser le CTE s'il n'est pas une expression triviale et le CTE est référencé plus d'une fois dans la requête". Il existe certaines requêtes pour lesquelles la matérialisation améliorera les performances. Il existe certaines requêtes pour lesquelles la matérialisation dégradera considérablement les performances. L'exemple suivant est un peu artificiel mais il illustre bien le point:
Créez d'abord une table avec une clé primaire qui contient des entiers de 1 à 10000:
Considérez la requête suivante qui utilise deux tables dérivées:
Nous pouvons examiner cette requête et déterminer rapidement qu'elle ne renverra aucune ligne. Oracle devrait également pouvoir utiliser l'index pour le déterminer. Sur ma machine, la requête se termine presque instantanément avec le plan suivant:
Je n'aime pas me répéter, alors essayons la même requête avec un CTE:
Voici le plan:
C'est vraiment un mauvais plan. Au lieu d'utiliser l'index, Oracle matérialise 10000 X 10000 = 100000000 lignes dans une table temporaire pour finalement retourner 0 lignes. Le coût de ce plan est d'environ 6 M, ce qui est beaucoup plus élevé que l'autre requête. La requête a pris 68 secondes pour se terminer sur ma machine.
Notez que la requête peut avoir échoué s'il n'y a pas suffisamment de mémoire ou d'espace libre dans l'espace disque logique temporaire.
Je peux utiliser l'
INLINE
indice non documenté pour empêcher l'optimiseur de matérialiser le CTE:Cette requête est capable d'utiliser l'index et se termine presque instantanément. Le coût de la requête est le même qu'avant, 11. Donc pour la deuxième requête, l'heuristique utilisée par Oracle l'a amené à choisir une requête avec un coût estimé à 6 M au lieu d'une requête avec un coût estimé à 11.
la source
Pour SQL Server,
WITH CTE
spécifie l'ensemble de résultats nommé temporaire, mais n'est requis que pour le premierCTE
. c'est à direMais ce n'est pas une sous-requête ou une sous-requête corrélée. Il y a des choses que vous pouvez faire avec un CTE ce que vous ne pouvez pas faire avec une sous-requête dans SQL Server, comme mettre à jour les tables référencées dans un CTE. Voici un exemple de mise à jour d'une table avec un CTE.
Une sous-requête serait quelque chose comme
Ou une sous-requête corrélée est ce que vous avez fourni dans votre PO si vous deviez référencer / joindre / limiter vos résultats en fonction de a.c1.
Donc, ce n'est certainement pas la même chose, mais dans de nombreux cas, vous pouvez utiliser une ou plusieurs de ces méthodes pour obtenir le même résultat. Cela dépend simplement de ce que ce résultat final est.
la source
La principale différence entre une
with
clause et une sous-requête dans Oracle est que vous pouvez référencer plusieurs fois une requête dans la clause. Vous pouvez ensuite faire quelques optimisations avec lui comme le transformer en une table temporaire en utilisantmaterialize
hint. Vous pouvez également effectuer des requêtes récursives avec lui en se référençant à l'intérieur d'unewith
clause. Vous ne pouvez pas faire cela avec une vue en ligne.Plus d'informations peuvent être trouvées ici et ici .
la source
MATERIALIZE
resp.INLINE
pour le contraire.materialize
indice est une option valide. J'avais parfois besoin de le spécifier lors de l'optimisation de requêtes très complexes où je savais que la matérialisation du CTE bénéficierait au plan d'exécution.Vous devez être prudent avec les CTE dans SQL Server et pas seulement avec Oracle, il y a des cas où les requêtes sont bien plus mauvaises lorsque vous utilisez des CTE par rapport aux sous-requêtes, des applications croisées, etc.
Comme toujours, il est important de tester toute requête dans différentes conditions de charge pour déterminer celle qui fonctionne le mieux.
Semblable à @scsimon avec oracle, parfois MS SQL Server ne fait pas ce que vous attendez en ce qui concerne l'utilisation des index.
Si vous allez utiliser les mêmes données plus d'une fois, les CTE peuvent être plus utiles, si vous ne les utilisez qu'une seule fois, souvent une sous-requête est plus rapide dans les grands ensembles de données.
par exemple, sélectionnez * dans (ma sous-requête), joignez autre chose ...
la source