Introdução às Common Table Expressions (CTEs)
As CTEs são uma maneira poderosa de organizar e simplificar consultas SQL complexas. Usando a cláusula WITH, você pode criar expressões temporárias que melhoram a legibilidade, manutenção e, em alguns casos, o desempenho das consultas.
Elas são especialmente úteis em cenários onde a mesma subconsulta é utilizada repetidamente, ou quando uma consulta possui muitos níveis de aninhamento. Além disso, CTEs são mais legíveis do que subconsultas tradicionais e podem reduzir o overhead computacional, dependendo do otimizador do banco de dados.
Exemplos de uso
WITH table_example AS (
-- Subconsulta
SELECT coluna1, coluna2
FROM tabela
WHERE condição
)
SELECT *
FROM table_example;
No próximo exemplo é possível ver uma query sem o uso do WITH e outra adotando a solução:
SELECT cod_cliente, COUNT(*) AS tot_vendas
FROM vendas
WHERE status = 'FINALIZADO'
GROUP BY cod_cliente;
SELECT cod_cliente, SUM(vl_pedido) AS tot_valor
FROM vendas
WHERE status = 'FINALIZADO'
GROUP BY cod_cliente;
Solução aplicando o WITH:
WITH vendas_realizadasAS (
SELECT cod_cliente, vl_pedido
FROM vendas
WHERE status = 'FINALIZADO'
)
SELECT cod_cliente, COUNT(*) AS tot_vendas, SUM(vl_pedido) AS tot_valor
FROM vendas_realizadas
GROUP BY cod_cliente;
Nos exemplos acima vemos como a consulta fica mais clara e legível com o uso do CTE, permitindo assim um fácil entendimento bem como uma melhoria de perfomance e evirando repetição de queries, que são vantagens que buscamos com a utilização do CTE.
Assim como no caso abordado acima, existem outros exemplos do uso da clausula WITH fazendo JOIN com outras tabelas e criando assim consultas mais complexas.
Um exemplo de utilização fazendo JOIN com outras tabelas é possível ver abaixo onde listamos os funcionários que não são gerentes, ou seja, que não possuem subordinados:
WITH subordinados AS (
SELECT id_gerente AS gerente_id
FROM funcionarios
WHERE id_gerente IS NOT NULL
)
SELECT f.id_funcionario, f.nome
FROM funcionarios f , subordinados s
WHERE f.id_funcionario = s.gerente_id
AND s.gerente_id IS NULL;
Para finalizar, um ponto importante no banco de dados Oracle, é que as CTEs são frequentemente materializadas (inline view). Isso significa que a consulta é executada uma vez e reutilizada, reduzindo o overhead. Podemos usar o hint /*+ MATERIALIZE */ para forçar a materialização se necessário.
WITH /*+ MATERIALIZE */ cte_table_name AS (
SELECT ...
)
SELECT ...
FROM cte_table_name;
Benefícios do uso do WITH
Melhoria na Legibilidade e Manutenção
- Ao nomear subconsultas, o SQL se torna mais legível e mais fácil de ajustar.
Reuso de Resultados
- Você pode referenciar a mesma CTE múltiplas vezes em uma consulta.
Simplificação de Consultas Complexas
- Quebre consultas aninhadas ou cálculos complicados em blocos lógicos.
Redução de Carga Computacional (em alguns casos)
- CTEs materiais podem ser calculadas uma vez e reutilizadas, economizando esforço computacional.
Compatibilidade com Recursão
- CTEs permitem consultas recursivas, que são úteis para hierarquias e estruturas de dados como árvores.
Um dos pontos de ateção é evitar o uso para queries simples, uma vez que isso poderá ocasionar o efeito contrário do desejado e adicionar uma complexidade desnecessário reduzindo a eficiência.
Conclusão
O uso de CTEs é uma boa abordagem para simplificar e organizar consultas SQL complexas, reduzir duplicação de código e, em alguns casos, melhorar a performance. Apesar disso, é importante testar sua aplicação em diferentes cenários, pois a performance pode variar dependendo do otimizador do banco de dados e do tamanho dos dados envolvidos, e assim não gerar os ganhos inicialmente esperados.
Espero que assim como nos demais posts, o tópico abordado tenha contribuído no entendimento de mais essa opção existente dentre as inúmeras outras relacionados ao contexto de banco de dados.
Referências
Os ctes tem performance melhor do que as subqueries?
Olá Antonio,
CTEs são mais legíveis do que subconsultas (subqueries) tradicionais e podem reduzir o overhead computacional, dependendo do otimizador do banco de dados. No caso do WITH a query é executada uma vez para pegar os dados e retornar para o restante da query, já nas subqueries é feito mais de uma execução, o que explica essa redução de overhead.
Obrigado pelo comentário.