No nosso último artigo, entendemos como os índices funcionam como o “índice remissivo” de um livro, salvando a performance das nossas buscas. Mas até agora, estávamos olhando para uma única tabela por vez.
Na vida real — e principalmente em arquiteturas de dados complexas e microsserviços —, as informações são normalizadas e divididas em várias tabelas para evitar redundância.
Você tem uma tabela para servidores, outra para clusters e uma terceira para regioes_cloud. Como juntar tudo isso em uma única consulta sem transformar o seu banco de dados em um gargalo? É aqui que entram os JOINs.
O que é um JOIN e por que ele é necessário?
O banco de dados relacional recebe esse nome justamente porque as tabelas se relacionam entre si por meio de chaves primárias (PRIMARY KEY) e chaves estrangeiras (FOREIGN KEY).
O JOIN é a cláusula que diz ao PostgreSQL para cruzar as linhas de duas ou mais tabelas baseando-se em uma coluna comum entre elas.
Para os exemplos abaixo, imagine que temos duas tabelas:
servidores(com a colunaid_cluster)clusters(com a colunaid)
Os Tipos de JOIN mais comuns (e quando usar cada um)
Existem diferentes formas de conectar tabelas, dependendo se você quer trazer apenas os dados correspondentes ou incluir dados que sobram de um dos lados.
1. INNER JOIN (A Interseção)
É o tipo mais utilizado. Ele retorna registros apenas quando houver uma correspondência exata em ambas as tabelas. Se um servidor não estiver associado a nenhum cluster, ele não aparece no resultado.
SELECT s.nome AS servidor, c.nome AS cluster
FROM servidores s
INNER JOIN clusters c ON s.id_cluster = c.id;
Dica de sintaxe: Usamos s e c como apelidos (aliases) para as tabelas para deixar a query mais limpa e evitar ambiguidade nas colunas.
2. LEFT JOIN ou LEFT OUTER JOIN (Garantindo o lado esquerdo)
Retorna todos os registros da tabela da esquerda (servidores), mesmo que não haja correspondência na tabela da direita (clusters). Se um servidor estiver sem cluster, as colunas do cluster virão como NULL.
Muito útil para cenários de auditoria em DevOps, como encontrar recursos “órfãos” na infraestrutura:
SELECT s.nome AS servidor, c.nome AS cluster
FROM servidores s
LEFT JOIN clusters c ON s.id_cluster = c.id;
3. RIGHT JOIN (Garantindo o lado direito)
É o inverso do LEFT JOIN. Traz todos os registros da tabela da direita (clusters), mesmo que não haja nenhum servidor associado a eles. (Na prática do mercado, a maioria dos profissionais prefere inverter a ordem das tabelas e usar LEFT JOIN por legibilidade, mas é vital conhecer o funcionamento).
Como o PostgreSQL executa um JOIN (O olhar DevOps)
Quando você roda um JOIN, o motor do Postgres não faz mágica. Ele adota estratégias de algoritmo baseadas no tamanho das tabelas e nos índices disponíveis. As três abordagens principais do Postgres são:
- Nested Loop: Ele pega uma linha da Tabela A e varre a Tabela B inteira procurando o par. Faz isso para cada linha. É excelente para tabelas pequenas, mas um desastre para tabelas gigantes se não houver índices.
- Hash Join: Ele carrega a tabela menor na memória, cria uma tabela hash e depois cruza com a tabela maior. É muito rápido, mas consome memória RAM do servidor (
work_mem). - Merge Join: Se ambas as tabelas já estiverem ordenadas (geralmente por causa de índices), o Postgres apenas desliza pelas duas em paralelo, cruzando os dados. É a forma mais eficiente para grandes volumes.
Boas Práticas para JOINs Performáticos
- Indexe suas Chaves Estrangeiras: O Postgres quase sempre vai precisar buscar a correspondência da chave estrangeira. Se a coluna
id_clusterna tabela de servidores não tiver um índice, o banco será forçado a fazer um Nested Loop com Sequential Scan, o que vai degradar a performance absurdamente. - Não abuse da quantidade de JOINs: Fazer uma query com 10 ou 15 JOINs força o otimizador do banco a calcular bilhões de combinações possíveis para achar o melhor plano de execução, o que consome CPU antes mesmo da query começar a trazer os dados.
- Filtre antes de juntar (quando aplicável): Sempre que possível, utilize a cláusula
WHEREpara reduzir o volume de dados de uma das tabelas antes que o banco tente realizar o cruzamento.
Conclusão
Entender a lógica e os tipos de JOIN é o divisor de águas para qualquer desenvolvedor, dba ou engenheiro de dados. Escrever um JOIN correto garante a integridade do seu relatório, e escrevê-lo de forma performática garante que a sua aplicação aguente o tranco em ambiente de produção.
Mas e quando a query com múltiplos JOINs começa a ficar lenta, como você descobre qual das junções ou qual tabela está pesando mais? Como “olhar o motor de busca” do Postgres?
No próximo post da nossa série de SQL, vamos aprender a usar a ferramenta definitiva de diagnóstico de performance: o comando EXPLAIN. Vamos aprender a ler o plano de execução do banco e descobrir exatamente onde a sua query está engasgando. Até lá!
Você costuma usar mais INNER JOIN ou LEFT JOIN no seu dia a dia? Já pegou algum relatório travando o banco por falta de índice em uma Foreign Key? Deixe sua história aqui nos comentários!