Benefícios da Common Table Expression (CTE)?

21

Do msdn :

Ao contrário de uma tabela derivada, uma CTE pode ser auto-referenciada e pode ser referenciada várias vezes na mesma consulta.

Estou usando CTEs bastante, mas nunca pensei profundamente sobre os benefícios de usá-los.

Se eu referenciar um CTE várias vezes na mesma consulta:

  • Existe algum benefício de desempenho?
  • Se eu estiver fazendo uma associação automática, o SQL Server verificará as tabelas de destino duas vezes?
Royi Namir
fonte
2
O Profiler deve informar se ele digitaliza duas vezes. IMHO, CTE são impressionantes para recursão.
Dan Andrews
3
Não há respostas concretas quando o otimizador de consultas está em execução. Algumas consultas terão benefícios de desempenho, outras não. Às vezes, usar uma tabela temporária em vez de um CTE será mais rápido, outras vezes não.

Respostas:

25

Como regra, um CTE NUNCA melhorará o desempenho .

Um CTE é essencialmente uma visão descartável. Não há estatísticas adicionais armazenadas, nenhum índice, etc. Ele funciona como um atalho para uma subconsulta.

Na minha opinião, eles podem ser facilmente superutilizados (vejo muito uso excessivo de código no meu trabalho). Algumas boas respostas estão aqui, mas se você precisar se referir a algo mais de uma vez, ou mais do que algumas centenas de milhares de linhas, coloque-o em uma #temptabela e indexe-o.

JNK
fonte
3
Aceita. Exceto para CTEs recursiva, então eles simplesmente ajudar a legibilidade
gbn
E se o CTE retornar apenas algumas linhas (para que possam ser mantidas na memória) que são caras de calcular (agregação em uma tabela grande) e esse resultado for usado mais de uma vez? Isso deve melhorar o desempenho, não deveria? (pelo menos essa é a minha experiência com PostgreSQL e Oracle, onde tabela temporária são usados muito raramente)
a_horse_with_no_name
2
@a_horse_with_no_name - seria equivalente a apenas torná-la uma subconsulta. Se o resultado for usado mais de uma vez em uma única consulta, será reutilizado e não recalculado. Se for usado em mais de uma consulta, a CTEé uma má escolha, pois os resultados são descartados após a primeira consulta.
JNK
@JNK: obrigado. Parece que o SQL Server se comporta de maneira diferente aqui.
a_horse_with_no_name
Algumas pessoas acham do CTE mais legível, em certas circunstâncias FWIW stackoverflow.com/a/11170918/32453
rogerdpack
14

Um lugar além da recursão, onde acho as CTEs incrivelmente úteis, é ao criar consultas complexas de relatórios. Uso uma série de CTEs para obter trechos dos dados de que preciso e depois combinar na seleção final. Acho que eles são mais fáceis de manter do que fazer a mesma coisa com muitas tabelas derivadas ou 20 junções e acho que posso ter mais certeza de que eles retornam os dados corretos sem o efeito de vários registros devido aos vários relacionamentos em todas as diferentes junções. Deixe-me dar um exemplo rápido:

;WITH Conferences (Conference_id)
AS 
(select  m.Conference_id
FROM mydb.dbo.Conference m 
WHERE client_id = 10
    and Conference_id in 
            (select Conference_id from mydb.dbo.Expense 
            where amount <>0
            and amount is not null)
     )
--select * from Conferences
,MealEaters(NumberMealEaters, Conference_id, AttendeeType)
AS
(Select count(*) as NumberMealEaters, m.Conference_id,  AttendeeType 
from mydb.dbo.attendance ma 
join Conferences m on m.Conference_id = ma.Conference_id
where (ma.meals_consumed>0 or meals_consumed is null)and attended = 1
group by m.Conference_id)
--select * from MealEaters

,Expenses (Conference_id,expense_date, expenseDescription,  RecordIdentifier,amount)
AS
(select Conference_id,max(expense_date) as Expense_date, expenseDescription,  RecordIdentifier,sum(amount) as amount
    FROM
        (SELECT Conference_id,expense_date,  amount, RecordIdentifier
        FROM mydb.dbo.Expense
        WHERE  amount <> 0 
            and Conference_id IN 
            (SELECT  Conference_id
            FROM mydb.dbo.Conferences ) 
        group by Conference_id, RecordIdentifier) a
)
--select * from Expenses
Select m.Conference_id,me.NumberMealEaters, me.AttendeeType, e.expense_date,         e.RecordIdentifier,amount
from Conferences m
join mealeaters me on m.Conference_id = me.Conference_id
join expenses e on e.Conference_id = m.Conference_id

Portanto, separando os diferentes blocos de informações que você deseja, você pode verificar cada parte individualmente (usando as opções comentadas, descomentando cada uma individualmente e executando apenas até a seleção selecionada) e se você precisou fazer uma alteração nas despesas cálculo (neste exemplo), é mais fácil encontrar do que quando todos eles são misturados em uma consulta massiva. Obviamente, as consultas de relatórios reais para as quais uso são geralmente muito mais complicadas do que o exemplo.

HLGEM
fonte
1
Apenas para relatar consultas? Os sistemas em que trabalho todos os dias têm consultas de transação que são complicadas. Estranhamente, nossas consultas de relatórios geralmente são algumas das mais simples. (Excluindo consultas CRUD sem associação triviais, é claro).
Kevin Cathcart
Eu usei isso como exemplo, porque esses geralmente são os mais complicados aqui
HLGEM 6/12/12
+1 às vezes é preferível uma consulta mais lógica (legível por humanos) do que uma potencialmente com melhor desempenho.
precisa saber é o seguinte
Sim. Dado que um CTE geralmente produz o mesmo plano resultante, não vejo razão para criar monstruosidades horrivelmente aninhadas e com várias subconsultas - quando poderíamos colocar cada componente visualmente na ordem em que são necessários. Eu importo arquivos XML e faço várias acrobacias para obter os dados da forma correta, o que seria insuportável para escrever / ler sem CTEs. (Alguns dos meus código antigo, provavelmente, tem subqueries horríveis todo!)
underscore_d
0

Como sempre, depende, mas há casos em que o desempenho é bastante aprimorado. Eu o vejo com instruções INSERT INTO SELECT, nas quais você usa um CTE para o select e depois o usa no INSERT INTO. Pode ter a ver com o RCSI estar ativado no banco de dados, mas nos momentos em que muito pouco é selecionado, pode ajudar bastante.

Ron S
fonte