Diferença entre CTE e SubQuery?


143

A partir desta postagem Como usar o ROW_NUMBER no procedimento a seguir?

Existem duas versões de respostas em que uma usa uma sub-querye a outra usa umaCTE para resolver o mesmo problema.

Agora, qual é a vantagem de usar CTE (Common Table Expression)uma 'subconsulta' em excesso (portanto, mais legível que a consulta está realmente fazendo)

A única vantagem de usar um CTEover sub-selecté que eu posso realmente nomear o sub-query. Existem outras diferenças entre os dois quando um CTE é usado como um CTE simples (não recursivo)?


Pergunta derivada com boa discussão: stackoverflow.com/q/11169550/781695
user

7
Na IMO, quem pensa que um CTE é menos legível que uma gigantesca bolha de subconsultas entrelaçadas não viu a pilha de lixo de consultas confusas em forma de dentes de serra em uso na maioria dos sistemas corporativos de gerenciamento de dados. Consultas grandes e não triviais são tipicamente muito mais fáceis de serem lidas mais tarde ou por novos olhos do que subconsultas, e pelo menos no caso do Postgres magicamente, o desempenho é muito melhor em muitos casos. ([Por razões que ainda têm de entender [( stackoverflow.com/questions/33731068/... ), como o oposto parece mais provável.)
zxq9

Respostas:


102

Nas versões CTE de subconsulta versus simples (não recursiva), elas são provavelmente muito semelhantes. Você precisaria usar o criador de perfil e o plano de execução real para identificar quaisquer diferenças, e isso seria específico da sua configuração (portanto, não podemos lhe dizer a resposta na íntegra).

Em geral ; Um CTE pode ser usado recursivamente; uma subconsulta não pode. Isso os torna especialmente adequados para estruturas de árvores.


1
Desculpe, eu deveria ter sido mais claro na minha pergunta. Qual seria a diferença entre CTE e Subquery no contexto em que CTE é usado como subconsulta?
dance2die

2
@ Marc Gravell: Podemos fazer mais do que isso, porém, como o comportamento do criador de perfil não é garantido, versus o comportamento do CTE, que é (em termos de avaliação).
CasperOne 01/04/09

1
Não tenho certeza do quanto essa afirmação faz sentido para as pessoas que observam a diferença entre CTS e subconsulta - A CTE can be used recursively; a sub-query cannot. Um exemplo teria sido ótimo.
Aniket Thakur

88

A principal vantagem da Common Table Expression (quando não a é usada para consultas recursivas ) é o encapsulamento. Em vez de declarar a subconsulta em todos os lugares em que você deseja usá-la, você pode defini-la uma vez, mas possui várias referências. para isso.

No entanto, isso não significa que ele seja executado apenas uma vez (como nas iterações anteriores desta resposta , obrigado a todos os que comentaram). A consulta definitivamente tem o potencial de ser executada várias vezes se referenciada várias vezes; o otimizador de consulta finalmente decide como a CTE deve ser interpretada.


"Pense em um CTE como uma variável da tabela temporária" significa que o CTE está armazenado no disco ou na memória?
dance2die

Você não pode usar o CTE ou a subconsulta em várias consultas, por definição. Tenho certeza que o otimizador lida com a subconsulta da mesma forma que iria lidar com o CTE (avaliando o conjunto de resultados apenas uma vez, independentemente de quantas vezes ele é usado dentro da consulta 1)
AlexCuse

@ AlexCuse: Acho que esclareci o contexto da CTE o suficiente, mas acrescentei mais para tentar esclarecer mais.
CasperOne 01/04/09

@AlexCuse: Também não há implicações de que o CTE ou a subconsulta possam ser usados ​​em vários locais. A diferença entre o CTE e o otimizador é que o comportamento do CTE é garantido, enquanto o comportamento do otimizador não é.
CasperOne 01/04/09

e vou admitir que pode haver alguns casos extremos em que o otimizador engasga e a subconsulta é avaliada mais de uma vez, mas ainda não encontrei. Então, novamente, eu uso CTE é sempre que posso;)
AlexCuse

15

CTEsão mais úteis para recursão:

WITH hier(cnt) AS (
        SELECT  1
        UNION ALL
        SELECT  cnt + 1
        FROM    hier
        WHERE   cnt < @n
        )
SELECT  cnt
FROM    hier

retornará @nlinhas (até 101). Útil para calendários, conjuntos de linhas simulados etc.

Eles também são mais legíveis (na minha opinião).

Além disso, são CTEe subqueriessão idênticos.


No MSSQL, você precisa adicionar um ponto-e-vírgula (;) antes de WITH; em ordem, você receberá um erro. deve ser;WITH blabla AS ...)
Obinna Nnenanya

2
@ObinnaNnenanya: somente se não for a primeira declaração do lote. Encerrar suas instruções com ponto-e-vírgula é uma boa ideia, mesmo que o SQL Server não a imponha nas versões atuais diferentes de antes WITH, MERGEe similares
Quassnoi

10

Uma diferença que não foi mencionada é que uma única CTE pode ser referenciada nas várias partes de uma união


8

A menos que esteja faltando alguma coisa, você pode nomear CTEs e subconsultas com a mesma facilidade.

Eu acho que a principal diferença é a legibilidade (acho o CTE mais legível porque define sua subconsulta antecipadamente e não no meio).

E se você precisar fazer alguma coisa com recursão, terá problemas para fazer isso com uma subconsulta;)


1
Não tenho certeza se existe alguma diferença não estética (embora eu espere que em determinadas situações possa haver pequenas diferenças no plano de execução). Quer me esclarecer?
AlexCuse

2
Você pode nomear CTEs, mas você pode apenas subconsultas de alias . A diferença é que você pode reutilizar CTEs com vários aliases (veja o exemplo de @Michael Petito em seu comentário ao casperOne). Não conheço nenhuma maneira de fazer isso com subconsultas.
kmote 12/01

7

Um fato importante que ninguém mencionou é que (pelo menos no postgres), os CTEs são cercas de otimização:

https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/

Ou seja, eles serão tratados como sua própria consulta atômica, em vez de dobrados em todo o plano de consulta. Eu não tenho o conhecimento necessário para dar uma explicação melhor, mas você deve verificar a semântica da versão do sql que está usando; para usuários avançados, a capacidade de criar uma cerca de otimização pode ajudar no desempenho se você for especialista no controle do planejador de consultas; em 99% dos casos, no entanto, você deve evitar dizer ao planejador de consultas o que fazer, porque o que você acha que será mais rápido provavelmente é pior do que o que ele pensa que será mais rápido. :-)


6

Adicionando às respostas de outras pessoas, se você tiver uma e a mesma subconsulta usada várias vezes, poderá substituir todas essas subconsultas por uma CTE. Isso permite que você reutilize seu código melhor.


4

Uma coisa que você precisa entender também é que, nas versões mais antigas do SQL Server (sim, muitas pessoas ainda precisam oferecer suporte aos bancos de dados do SQL Server 2000), os CTEs não são permitidos e a tabela derivada é a melhor solução.


2

DICA: (MAXRECURSION n)

você pode limitar o número de níveis de recursão permitidos para uma instrução específica usando a MAXRECURSIONdica e um valor entre 0 e 32.767 na OPTIONcláusula

Por exemplo, você pode tentar:

OPTION 
      (MAXRECURSION 150)

GO
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.