Uma dúvida comum entre desenvolvedores e analistas de dados é:
Qual a diferença entre
EXISTS,INeJOIN?
Essas três abordagens podem retornar o mesmo resultado, mas possuem diferenças importantes de comportamento e performance, especialmente em bases grandes.
Para quem trabalha com ERP como o Protheus, onde as tabelas crescem rapidamente, entender essas diferenças ajuda a evitar consultas lentas e escolhas ruins de modelagem SQL.
Neste artigo, vamos analisar:
- como cada abordagem funciona
- quando usar cada uma
- diferenças práticas de performance
- exemplos com tabelas comuns do Protheus
Exemplo prático
Imagine duas tabelas comuns em um cenário de ERP:
SA1: cadastro de clientesSC5: cabeçalho de pedidos de venda
Queremos responder à seguinte pergunta:
Quais clientes possuem pedidos cadastrados?
1. Usando JOIN
Uma forma bastante comum é utilizar JOIN.
SELECT DISTINCT A1_COD, A1_NOME
FROM SA1
JOIN SC5
ON SC5.C5_CLIENTE = SA1.A1_COD
WHERE SA1.D_E_L_E_T_ = ''
AND SC5.D_E_L_E_T_ = ''
O que acontece aqui
O banco faz a junção entre SA1 e SC5.
Se um cliente tiver vários pedidos, ele poderá aparecer várias vezes no resultado. Por isso, neste caso, usamos DISTINCT para eliminar duplicidades.
Vantagens
- permite retornar dados das duas tabelas
- tem sintaxe bastante conhecida
- é uma boa escolha quando a relação entre os dados precisa ser exibida no resultado
Desvantagens
- pode gerar duplicidade de registros
DISTINCTpode aumentar o custo da consulta- nem sempre é a melhor opção quando você só quer verificar existência
2. Usando IN
Outra forma comum é usar IN.
SELECT A1_COD, A1_NOME
FROM SA1
WHERE A1_COD IN (
SELECT C5_CLIENTE
FROM SC5
WHERE D_E_L_E_T_ = ''
)
AND SA1.D_E_L_E_T_ = ''
Como funciona
A subquery executa e retorna uma lista de clientes que possuem pedidos. Depois disso, o banco compara A1_COD com essa lista.
Vantagens
- sintaxe simples
- fácil de entender e manter
- funciona bem quando a subconsulta retorna poucos valores
Possível problema
Se a subquery retornar muitos registros, essa abordagem pode ficar mais custosa, dependendo do otimizador e do banco utilizado.
3. Usando EXISTS
Agora a terceira abordagem.
SELECT A1_COD, A1_NOME
FROM SA1 A
WHERE A.D_E_L_E_T_ = ''
AND EXISTS (
SELECT 1
FROM SC5 C
WHERE C.C5_CLIENTE = A.A1_COD
AND C.D_E_L_E_T_ = ''
)
Como funciona
Para cada cliente em SA1, o banco verifica se existe ao menos um registro relacionado em SC5.
Assim que encontra o primeiro pedido correspondente, a busca pode ser encerrada.
Vantagens
- geralmente escala melhor em grandes volumes
- evita materializar listas desnecessárias
- não gera duplicidade no resultado final
- costuma ser a melhor opção quando o objetivo é apenas verificar existência
Diferença mental entre IN e EXISTS
Uma forma simples de memorizar:
| Abordagem | Pergunta que ela responde |
|---|---|
IN | O valor está dentro desta lista? |
EXISTS | Existe algum registro relacionado? |
Exemplos:
cliente IN (lista de clientes com pedidos)EXISTS (pedido onde cliente_id = cliente.id)
Exemplo em uma rotina AdvPL
Em uma rotina AdvPL utilizando SQL, você poderia montar a consulta assim com IN:
cQuery := "SELECT A1_COD, A1_NOME " + ;
"FROM SA1 " + ;
"WHERE A1_COD IN ( " + ;
" SELECT C5_CLIENTE " + ;
" FROM SC5 " + ;
" WHERE D_E_L_E_T_ = '' " + ;
") " + ;
"AND SA1.D_E_L_E_T_ = '' "
Versão alternativa utilizando EXISTS:
cQuery := "SELECT A1_COD, A1_NOME " + ;
"FROM SA1 A " + ;
"WHERE A.D_E_L_E_T_ = '' " + ;
"AND EXISTS ( " + ;
" SELECT 1 " + ;
" FROM SC5 C " + ;
" WHERE C.C5_CLIENTE = A.A1_COD " + ;
" AND C.D_E_L_E_T_ = '' " + ;
") "
Em bases grandes de ERP, essa troca pode fazer diferença perceptível no tempo de resposta.
Comparação rápida
| Método | Melhor uso |
|---|---|
JOIN | Quando você precisa retornar dados das duas tabelas |
IN | Quando trabalha com listas pequenas ou subconsultas simples |
EXISTS | Quando quer apenas verificar existência |
Regra prática
Uma regra bastante usada no dia a dia é:
- use
JOINquando precisar combinar e retornar colunas de duas tabelas - use
EXISTSquando quiser apenas saber se há relacionamento - use
INquando estiver lidando com listas pequenas ou valores fixos
Dica para quem trabalha com ERP
Em sistemas ERP, as tabelas podem crescer para milhões de registros. Nesses cenários:
EXISTScostuma escalar melhorJOINpode multiplicar linhas e exigirDISTINCTINpode se tornar menos eficiente com listas muito grandes
Sempre que possível, analise o plano de execução da consulta antes de assumir qual versão será a melhor.
Conclusão
EXISTS, IN e JOIN podem produzir o mesmo resultado em alguns cenários, mas não são equivalentes.
Resumo prático:
JOINquando você precisa trazer dados relacionadosINquando a comparação é com listas pequenasEXISTSquando a intenção é apenas validar existência
Conhecer essas diferenças ajuda a escrever SQL mais eficiente, previsível e escalável, principalmente em ambientes como o Protheus.
Leituras recomendadas
Se você trabalha com SQL no dia a dia, vale aprofundar também nestes temas:
NOT EXISTSvsNOT INLEFT JOINvsNOT EXISTSGROUP BYvsDISTINCT