← tópicos

Específicos · Bancos de Dados

Modelagem NoSQL: orientada a consultas, desnormalização, agregados

O relacional parte do dado e normaliza; aqui se parte da consulta e se duplica de propósito. O custo não some: sai da leitura e reaparece na escrita.

Média

Nenhum item de prova anterior, no acervo deste projeto, caiu neste tópico. A nota foi escrita a partir do edital e da bibliografia — não do corpus — e por isso não traz frequências medidas.

A ideia que organiza o assunto

A modelagem relacional começa pelos dados: descobre-se que entidades existem, normaliza-se para eliminar redundância, e só depois se escrevem as consultas — que o otimizador atende com junções, sejam elas quais forem. O modelo é independente da pergunta: um esquema normalizado responde bem a consultas que ninguém imaginou quando ele foi desenhado.

A modelagem NoSQL inverte a ordem. Começa-se pelas consultas: enumeram-se os padrões de acesso da aplicação — quem lê o quê, com que filtro, com que frequência, em que ordem — e projeta-se, para cada um deles, uma estrutura que o atenda em uma única leitura. Como o mesmo dado costuma ser necessário em padrões de acesso diferentes, ele é gravado em mais de um lugar, de propósito.

Isso não é normalização mal feita. É uma troca deliberada, e ela tem nome dos dois lados:

Daí decorrem as três consequências que organizam o resto da nota. Primeira: não se modela NoSQL sem conhecer as consultas — o modelo relacional errado custa desempenho; o modelo NoSQL errado custa a consulta, que simplesmente não pode ser feita. Segunda: o custo não desaparece, muda de lado — a leitura fica barata e a escrita fica cara, porque uma alteração lógica vira várias escritas. Terceira: quem decide onde a redundância começa e termina é o agregado, a unidade que é lida, gravada, replicada e distribuída como um bloco só.

Por que se usa (e o que custa)

O ganho é medido na leitura e na distribuição. Uma tela que no relacional exigiria sete junções vira um get por chave, e como o agregado é autocontido ele pode viver inteiro em um nó do cluster: a consulta não precisa falar com três máquinas, o que é exatamente o que permite escalar horizontalmente. O agregado é também a fronteira de atomicidade — bancos de chave-valor, de documentos e de famílias de colunas garantem escrita atômica dentro de um agregado, e nada além disso.

O custo tem três parcelas, e ignorá-las é o que produz item errado.

A escrita multiplica. Um nome de produto duplicado em cinquenta mil pedidos é uma atualização em cinquenta mil documentos. Enquanto ela corre, há uma janela em que as cópias divergem — consistência eventual não é só um slogan de CAP, é o estado real dos dados desnormalizados durante a propagação.

A aplicação herda a integridade. Não há chave estrangeira, não há CASCADE, não há restrição declarada que impeça a cópia de envelhecer. O que no relacional o SGBD garantia passa a depender de código — e de código que alguém precisa lembrar de escrever em todos os pontos de escrita.

O modelo endurece contra o futuro. Um padrão de acesso que ninguém previu não se resolve com um JOIN improvisado: resolve-se remodelando e reescrevendo os dados. É a rigidez que a flexibilidade de esquema esconde — e a razão de dado muito relacionado, consulta imprevisível e integridade forte continuarem sendo terreno do relacional.

Como funciona

1. Levantar os padrões de acesso. Antes de qualquer estrutura: quais são as consultas, quais filtram por quê, qual a proporção entre leitura e escrita, qual o volume e como ele cresce. Esse levantamento faz, aqui, o papel que o modelo conceitual faz lá — e o modelo conceitual não desaparece: entidades e relacionamentos continuam sendo levantados; o que muda é a tradução deles para o modelo lógico.

2. Desenhar a fronteira do agregado. A pergunta é: o que é lido junto e alterado junto? O que se lê junto entra no mesmo agregado; o que é acessado de forma independente, ou é compartilhado por muitos agregados, fica fora e é referenciado. Endereço de entrega pertence ao pedido; catálogo de produtos, não.

3. Embutir ou referenciar, pela cardinalidade. É a decisão concreta em banco de documentos:

Embuta também quando os dados mudam juntos; referencie quando a parte embutida mudaria com frequência muito maior que o todo.

4. Desnormalizar com intenção. A forma mais comum é a referência estendida: além da chave do outro documento, copiam-se os poucos campos que a tela precisa mostrar — o nome do cliente dentro do pedido, para não ter de buscar o cliente. Copia-se o que muda pouco; o que muda muito permanece referenciado. Outros padrões da mesma família guardam valores já calculados (totais, contadores) em vez de recalculá-los a cada leitura, e agrupam séries temporais em blocos — um documento por hora, com as leituras dentro, em vez de um documento por leitura.

5. Uma tabela por consulta, no colunar. Em Cassandra a regra é literal: modela-se uma tabela para cada consulta que a aplicação faz, duplicando os dados entre elas. A chave primária combina chave de partição (que determina em que nó o dado mora, e sem a qual a consulta não se faz) e colunas de agrupamento (que determinam a ordenação dentro da partição). A cláusula WHERE só aceita o que a chave permite, não há junção, e recorrer a ALLOW FILTERING é sinal de que o modelo não previu aquela consulta.

6. Manter as cópias em dia. Ou a aplicação escreve em todos os lugares na mesma operação, ou um processo assíncrono propaga a mudança depois, mais barato e com janela de divergência assumida. Nos dois casos a decisão é de quem modela — o banco não faz isso sozinho.

“NoSQL não tem esquema” é falso, e em três níveis. No mais literal, vários produtos exigem esquema declarado: Cassandra exige tabela criada com colunas tipadas, e Elasticsearch tem mapping, explícito ou inferido, que uma vez fixado não muda para um campo existente. No intermediário, os que não exigem oferecem validação opcional — bancos de documentos permitem declarar regras de validação por coleção. E no nível que interessa: mesmo sem nenhuma declaração, o esquema existe no código da aplicação, que espera certos campos com certos tipos. É o schema-on-read: a validação foi deslocada da escrita para a leitura, não suprimida. Documentos de formatos diferentes convivendo na mesma coleção obrigam o código a tratar todas as versões — por isso a prática de gravar um campo de versão do esquema.

O que decide os itens

par que a banca trocao que decide
Modelagem relacional × orientada a consultasO relacional parte dos dados e normaliza; o NoSQL parte das consultas e duplica. Ordem inversa, e é isso que o item inverte.
Normalizar × desnormalizarNormalizar elimina redundância e paga em junções; desnormalizar elimina junções e paga em escrita e em risco de divergência.
Custo eliminado × custo deslocadoA desnormalização não torna tudo mais barato: barateia a leitura e encarece a escrita e a manutenção.
Agregado × entidadeO agregado é a unidade de leitura, escrita, replicação e distribuição — e a fronteira da atomicidade. Pode reunir várias entidades.
Embutir × referenciarLido junto e alterado junto, embute; acessado à parte, compartilhado ou de crescimento ilimitado, referencia.
1:poucos × 1:incontáveisPoucos, embutidos; incontáveis, referenciados do lado muitos — documento que cresce sem limite é defeito de modelagem.
Integridade no SGBD × na aplicaçãoSem chave estrangeira e sem CASCADE, a coerência entre cópias é código da aplicação.
Schema-on-write × schema-on-readA validação mudou de momento, não deixou de existir. Cassandra e Elasticsearch exigem estrutura declarada.
“Sem esquema” × “esquema flexível”Flexível: campos podem variar entre documentos. Isso não é ausência de contrato — é contrato mantido fora do banco.
Modelo conceitual × modelo lógicoO conceitual permanece; muda a tradução para o lógico. NoSQL não dispensa modelagem: exige outra.
Agregado × grafoBancos de grafos são indiferentes a agregado: não se desnormaliza um grafo, percorrem-se arestas. A regra query-first não se aplica a eles do mesmo jeito.
Desnormalização dimensional × desnormalização NoSQLNo data warehouse, desnormaliza-se a dimensão por desempenho analítico; aqui, desnormaliza-se por padrão de acesso e ausência de junção. Mesmo movimento, motivos diferentes.
Uma tabela por consulta × uma tabela por entidadeNo colunar, a mesma informação vive em várias tabelas, uma por consulta. Não é erro de projeto: é o projeto.

Como a CEBRASPE derruba você aqui

Esta seção é julgamento sobre como a banca costuma cobrar o assunto — não medição. Não há itens deste tópico no acervo para medir.

A inversão da ordem do processo. É o item mais natural do tópico e o mais fácil de não ver: “na modelagem NoSQL, projeta-se primeiro a estrutura dos dados e, a partir dela, derivam-se as consultas”. A frase descreve corretamente o método — só que o método é o do relacional. Defesa: leia a descrição até o fim, decida sozinho a que abordagem ela pertence e só então confira o nome que o item deu.

A vantagem sem o custo. “A desnormalização melhora o desempenho de leitura e de escrita”, “elimina a necessidade de controle de consistência”, “reduz o espaço ocupado”. Todas soam plausíveis porque a primeira metade é verdadeira. O teste é sempre o mesmo: o que a desnormalização barateia é a leitura, e escrita, espaço e consistência vão na direção contrária.

“NoSQL dispensa modelagem” e suas variantes. “Dispensa a definição de modelo lógico”, “não admite esquema”, “a ausência de esquema impede a indexação”. O que existe é esquema validado na leitura ou declarado fora do banco; e há produtos que exigem declaração prévia. Quando o item negar a existência de esquema em bloco, ele está errado.

A fronteira do agregado trocada pela da entidade. Um item que trate agregado como sinônimo de tabela, ou que afirme que a atomicidade se estende a vários agregados, está apagando exatamente aquilo que o agregado define. Garantia atômica existe dentro de um agregado.

O documento sem limite. “Em um banco de documentos, recomenda-se embutir todas as ocorrências do lado muitos de um relacionamento.” Não se recomenda: há limite de tamanho de documento, e um arranjo que cresce indefinidamente torna cada leitura e cada escrita mais caras. Embute-se o que é pequeno e limitado.

Quando o absoluto é da definição. “O agregado é a unidade de distribuição”, “em Cassandra, toda consulta eficiente informa a chave de partição”, “os mesmos dados são intencionalmente repetidos em várias tabelas” — parecem exageros e são o desenho do modelo. A pergunta continua sendo de quem é o absoluto: do produto e da definição, ou do redator do item.

Erros clássicos

Achar que modelagem orientada a consultas é modelagem relacional sem normalizar. É outra ordem de trabalho: as consultas vêm antes das estruturas.

Tratar desnormalização como ganho sem contrapartida. Ela transfere o custo para a escrita e para a consistência entre as cópias.

Esperar que o banco mantenha as cópias coerentes. Não há chave estrangeira nem propagação automática: é código da aplicação ou processo assíncrono.

Embutir coleções ilimitadas. Documento que cresce sem teto estoura o limite de tamanho e encarece toda leitura.

Referenciar o que é sempre lido junto. O erro simétrico: obriga a segunda ida ao banco justamente onde o modelo existia para evitá-la.

Ler schemaless como ausência de contrato. O contrato mudou de lugar — está na aplicação, no mapping ou na validação da coleção.

Duplicar dados voláteis. Copia-se o que muda pouco; o campo que muda toda hora deve ficar referenciado, ou a divergência vira rotina.

Modelar um grafo como se fosse agregado. Em banco de grafos não se desnormaliza: o que dá desempenho é percorrer arestas, e o modelo é próximo do conceitual, não derivado das consultas.

Tratar a modelagem como definitiva. Padrão de acesso novo pode exigir estrutura nova e reescrita dos dados: é o preço de ter otimizado para os padrões conhecidos.

Nenhum item do acervo cai neste tópico. A leitura é o conteúdo aqui.