Seu Sistema Está Engasgando com Hierarquias? Aprenda Como o Padrão Nested Sets Pode Salvar a Performance do Seu Banco de Dados

Você tem um sistema com categorias, menus, estruturas organizacionais ou árvores de decisão?
E quando precisa consultar uma subárvore ou exibir todos os filhos de um item, sua query parece um labirinto com JOINs recursivos ou CTEs malucos?

Se você está sofrendo para lidar com estruturas hierárquicas em um banco de dados relacional, o problema não está no SQL — está na modelagem.

E o padrão Nested Sets pode ser a solução simples, elegante e poderosa que você estava ignorando.


📌 O que é Nested Sets?

Nested Sets é um padrão de modelagem usado para armazenar estruturas em árvore (hierarquias) em bancos relacionais como PostgreSQL, MySQL, Oracle, SQL Server, etc.

A mágica acontece com dois campos numéricos: left e right.

Esses campos representam a posição do nó dentro da árvore, como se você estivesse percorrendo a árvore com um “número de entrada” e “número de saída”.


🧠 Como Funciona (Para Humanos)

Imagine que você vai visitar cada nó da árvore, seguindo a ordem “profundidade antes da largura” (depth-first traversal).
Você dá um número ao entrar no nó (left) e outro ao sair (right).

🌳 Exemplo visual da árvore:

scssCopiarEditarEletrônicos (1, 10)
├── Computadores (2, 5)
│   ├── Notebooks (3, 4)
├── Celulares (6, 9)
│   ├── Smartphones (7, 8)
idnomeleftright
1Eletrônicos110
2Computadores25
3Notebooks34
4Celulares69
5Smartphones78

💡 O Que Dá Pra Fazer com Nested Sets

✅ 1. Buscar todos os filhos de um nó:

SELECT * FROM categorias
WHERE left > 2 AND right < 5;

Resultado: Notebooks (filho de Computadores)

✅ 2. Buscar todos os ancestrais de um nó:

SELECT * FROM categorias
WHERE left < 3 AND right > 4;

Resultado: Computadores e Eletrônicos (pais de Notebooks)

✅ 3. Buscar subárvore inteira ordenada:

SELECT * FROM categorias
WHERE left BETWEEN 2 AND 5
ORDER BY left;

🔍 Por Que Usar Nested Sets?

Se você já usou o famoso padrão parent_id, sabe o pesadelo que é recuperar uma subárvore completa:

WITH RECURSIVE arvore AS (
SELECT * FROM categorias WHERE id = ?
UNION ALL
SELECT c.* FROM categorias c
JOIN arvore a ON c.parent_id = a.id
)
SELECT * FROM arvore;

Esse tipo de consulta:

  • Funciona? Sim.
  • Escala bem? Depende.
  • É simples de manter? Nem um pouco.

⚡️ Nested Sets resolve isso com:

  • Uma query simples
  • Leitura rápida
  • Menos processamento

⚠️ Mas Nem Tudo São Flores…

A maior crítica ao padrão Nested Sets é:

Inserir ou mover nós exige recalcular os valores left e right de vários registros.

Ou seja: ele é ótimo para leitura intensa, mas custoso para escrita dinâmica.


🧪 Como Inserir um Nó Novo

  1. Pegue o right do pai.
  2. Atualize todos os nós com left > pai.right e right ≥ pai.rightsome 2
  3. Insira o novo nó com: sqlCopiarEditarleft = pai.right right = pai.right + 1

Exemplo em SQL:

-- Atualizar os outros nós
UPDATE categorias SET right = right + 2 WHERE right >= 5;
UPDATE categorias SET left = left + 2 WHERE left > 5;

-- Inserir novo filho
INSERT INTO categorias (nome, left, right) VALUES ('Impressoras', 5, 6);

🧾 Comparando com Outras Estratégias

EstratégiaLeitura de SubárvoreInserçãoComplexidade
parent_idLenta (JOINs/recursão)RápidaBaixa
Nested SetsMuito rápidaLenta/moderadaMédia
Materialized PathRazoávelRazoávelMédia
Closure TableRápidaMédiaAlta


🧑‍💻 Quando Usar Nested Sets?

✅ Use quando:

  • Sua árvore não muda com frequência
  • A leitura de subárvores é mais comum do que inserções
  • Você quer consultas simples e rápidas para UI, menus, navegação, relatórios hierárquicos

❌ Evite quando:

  • Você insere, remove ou move muitos nós com frequência
  • Precisa manter versão histórica das árvores

🛠️ Exemplo de Tabela no PostgreSQL

CREATE TABLE categorias (
id SERIAL PRIMARY KEY,
nome VARCHAR(100),
left INTEGER NOT NULL,
right INTEGER NOT NULL
);

📚 Bônus: Frameworks e ORMs com Suporte

Alguns ORMs (como Doctrine no PHP e Hibernate com extensões) têm suporte para Nested Sets via anotações ou extensões customizadas, mas geralmente você precisa cuidar da lógica de atualização manualmente.

No Java com JPA, você pode usar:

@Entity
public class Categoria {
@Id
private Long id;

private String nome;
private Integer left;
private Integer right;
}

A lógica de atualização pode ficar em um serviço de domínio dedicado, usando transações com @Transactional.


🏁 Conclusão

Se você quer desempenho real nas consultas de árvore sem recorrer a CTEs recursivas e JOINs complicados, o Nested Sets é um padrão que vale aprender e usar.

É uma técnica poderosa, com mais de 20 anos de uso em bancos relacionais, e continua extremamente relevante em:

  • Sistemas de categorias
  • Menus dinâmicos
  • Sistemas hierárquicos
  • Aplicações que priorizam leitura rápida