# Modelos NoSQL e decisões de armazenamento

Documentos, chave-valor, colunas e grafos, com os custos de referências, duplicação e consistência.

Página: https://resumos.rgo.pt/cadeiras/lbaw/nosql/

Uma compra pode ser lida como um documento com os bilhetes adquiridos, ou reconstruída a partir de tabelas ligadas por chaves. A escolha depende das operações e garantias necessárias. **NoSQL** reúne famílias de sistemas com organizações diferentes; o nome não garante ausência de esquema, maior velocidade ou um contrato único de transações.

## Escolher a estrutura pela operação

| Modelo | Organização | Operação típica |
| --- | --- | --- |
| Chave-valor | Valor encontrado por chave. | Procurar uma sessão por identificador. |
| Documentos | Registos com campos e estruturas aninhadas. | Obter uma compra com os seus bilhetes. |
| Famílias de colunas | Linhas e colunas organizadas para padrões de acesso próprios. | Ler séries por chave e intervalo. |
| Grafos | Nós e relações com propriedades. | Percorrer ligações entre pessoas ou entidades. |

Um grafo é útil quando relações e percursos são centrais. Isso não torna toda a associação N:N um motivo para abandonar tabelas. Uma base chave-valor é adequada a uma procura por chave, mas uma pesquisa arbitrária por campos pode precisar de estruturas adicionais.

## Documento embebido ou referência

Uma compra da Loja de Bilhetes pode guardar os bilhetes num documento:

```
{
  "id": "C12",
  "comprador": "U7",
  "bilhetes": [
    { "codigo": "B1", "sessao": "S12", "preco_compra": 10 },
    { "codigo": "B2", "sessao": "S12", "preco_compra": 10 }
  ]
}
```

Os bilhetes são lidos com a compra C12. O preço de cada bilhete é o contratado, não o preço atual da sessão. Guardá-lo é um **snapshot histórico** intencional: uma subida do preço de S12 não altera os 20 euros desta compra. Duplicar o email atual de U7 em todas as compras é diferente, pois mudar esse email exigiria sincronizar vários documentos.

Se a compra tem poucos bilhetes, um limite explícito e é normalmente lida inteira, embeber pode ser adequado. Se cada bilhete muda frequentemente de estado por uma operação independente, compara esse custo com o de guardar referências. Não estendas esta decisão a uma lista ilimitada de todas as compras de U7.

**Embeber** aproxima dados lidos em conjunto e pode permitir uma operação atómica sobre um documento. **Referenciar** evita certas repetições e dá identidade independente, mas pode exigir consultas adicionais ou junções suportadas pelo sistema. Considera tamanho e crescimento: uma lista sem limite de todas as compras de uma pessoa não é uma boa escolha só porque pode ser embebida.

Um esquema flexível continua a precisar de validação de tipos, campos obrigatórios e versões. A aplicação tem de saber como ler documentos antigos. Uma migração deixa de ser necessária para certas alterações físicas, mas não desaparece a evolução do significado dos dados.

## Atomicidade e índices dependem do sistema

Não assumas que a atualização de dois documentos é atómica porque a atualização de um o é. Alguns sistemas suportam transações de várias operações em configurações adequadas, mas isso tem custos e requisitos próprios. Verifica o contrato do sistema e da versão antes de desenhar a unidade de atualização.

Documentos também precisam de índices para consultas seletivas: guardar JSON não torna a pesquisa gratuita. Uma base relacional pode guardar JSON e uma base de documentos pode validar um esquema; formato e garantias são dimensões diferentes, por isso compara sistemas por operação e não por rótulo.

Para impedir duas reservas do mesmo lugar, especifica unicidade, coordenação e semântica de repetição. Mudar de tecnologia não retira a necessidade de um [protocolo concorrente](https://resumos.rgo.pt/cadeiras/lbaw/triggers-transacoes/).

## CAP: uma escolha durante uma partição

No teorema CAP, **consistência** refere-se ao contrato de consistência forte usado no modelo, normalmente explicado como linearizabilidade, não à letra C de ACID. **Disponibilidade** exige resposta de cada nó não falhado a cada pedido no modelo. Uma **partição** impede comunicação entre grupos de nós.

Imagina duas réplicas de S12 separadas por uma falha de rede. Ambas começam com um lugar livre. Se cada lado aceitar uma reserva, podem confirmar duas compras incompatíveis com a capacidade. Preservar a consistência forte pode exigir recusar ou esperar por coordenação num dos lados, deixando de satisfazer disponibilidade no modelo.

Durante essa partição, não se pode garantir simultaneamente a consistência e a disponibilidade assim definidas. Um grupo pode recusar uma operação para não aceitar um estado incompatível, ou responder com informação que ainda não foi coordenada. Não é uma regra genérica «escolhe sempre duas de três», independente de falhas e da operação.

**Consistência eventual** significa que réplicas convergem sob condições como cessarem atualizações e a comunicação recuperar. Não significa que uma leitura imediatamente depois de uma escrita veja sempre essa escrita. Para uma reserva, esse detalhe pode mudar a correção da operação.

## Justificar uma escolha

Uma resposta completa identifica as consultas principais, as invariantes, a unidade de atualização, o volume e crescimento dos dados e as garantias necessárias, e só depois compara soluções. «NoSQL é mais escalável» não explica como distribui os dados nem que custo aceita.

## Exercícios

Verificar a unidade garantida

Uma escrita atómica num documento garante atomicidade entre dois documentos?

Pista

Distingue a unidade de escrita.

Mais uma pista

Consulta a versão e a configuração do sistema.

Solução

Não há inferência automática. Define se precisas de transação entre documentos e verifica o suporte e o custo.

*   **Não. É preciso um contrato específico para a operação composta..** Alguns sistemas têm transações, mas a garantia não decorre só da escrita simples.
*   **Sim, qualquer NoSQL tem essa garantia..** NoSQL reúne sistemas com contratos diferentes.
*   **Não, nenhum sistema NoSQL suporta transações..** Há sistemas com transações multidocumento.

Erros frequentes

Não generalizes a partir do nome NoSQL.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/lbaw/nosql/#atomicidade-e-%C3%ADndices-dependem-do-sistema)

Compra embebida e reserva distribuída

A compra C12 tem dois bilhetes e o limite por compra é dez. É normalmente lida inteira e raramente alterada; cada bilhete conserva o preço contratado. Decide se embeber os bilhetes é razoável. A capacidade de S12 fica noutro documento: atualizar C12 atomicamente garante a reserva? Por fim, duas réplicas de S12, cada uma com um lugar livre, deixam de comunicar. Podem ambas aceitar uma reserva mantendo consistência forte e disponibilidade no modelo CAP?

Pista

Separa o documento lido, a invariante entre documentos e a comunicação entre réplicas.

Solução

Embeber é razoável para esta leitura conjunta e lista limitada. O preço contratado é histórico e não deve acompanhar alterações do preço atual de S12. Os dois bilhetes não justificam embeber também todas as compras ilimitadas de U7.

Atomicidade de C12 não garante atualização conjunta com o documento de capacidade. A reserva exige o contrato adequado do sistema, como transação multidocumento e coordenação de escritores.

Durante a partição, aceitar independentemente em ambos os lados pode confirmar dois bilhetes para um lugar. Preservar consistência forte exige que alguma operação não receba a resposta de sucesso independente, por exemplo recusando-a ou esperando por coordenação. Isso sacrifica disponibilidade no modelo. Convergir mais tarde não apaga a incompatibilidade dos dois sucessos já prometidos.

Confere a tua resposta:

*   Justifico unidade de leitura e crescimento limitado.
*   Distingo preço histórico de dados atuais.
*   Não deduzo atomicidade entre compra e capacidade.
*   Aplico CAP ao caso de partição.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/lbaw/nosql/#documento-embebido-ou-refer%C3%AAncia)
