Banco de dados: arquitetura, modelos e garantias do SGBD
Quase toda aplicação crítica tem um banco de dados no caminho. Mesmo assim, boa parte dos times que opera sistemas em produção raramente abre a caixa. Poucos sabem o que acontece lá dentro quando uma query é executada.
Este artigo trata de banco de dados pela perspectiva de engenharia. Em vez de repetir a definição genérica, o foco é arquitetural. A pauta é como um SGBD organiza as camadas internas e por que alguns modelos servem para certos workloads e outros não. Também entram a implementação das garantias transacionais e os pontos que toda equipe de operações acaba monitorando mais cedo ou mais tarde.
A leitura serve a quem programa, opera ou arquiteta sistemas e quer parar de tratar o banco como caixa preta. Cada seção foi pensada para conectar conceito com sinal operacional, porque é exatamente nessa ponte que decisões de design e de monitoramento nascem.
O que é banco de dados: a definição que importa para quem opera
Um banco de dados é uma coleção organizada de dados persistida em um meio durável e acessada por múltiplos consumidores simultaneamente. Essa definição parece genérica, mas três palavras carregam as garantias mais difíceis de entregar: organizada, persistida e múltiplos consumidores.
Na prática, qualquer sistema que combine essas três propriedades precisa resolver problemas incompatíveis entre si. Organizar dados exige esquema ou estrutura. Persistir exige durabilidade diante de falhas de energia ou kernel panic. Concorrência exige ordenação de operações que chegam ao mesmo tempo pedindo leitura e escrita no mesmo recurso.
É por isso que existe uma distinção importante entre banco de dados e SGBD (sistema de gerenciamento de banco de dados). O banco é o dado organizado. O SGBD é o software que orquestra acesso, concorrência, durabilidade, indexação e recuperação. Quando alguém diz “estou usando PostgreSQL”, está se referindo ao SGBD. O banco é o conjunto de tabelas que esse SGBD gerencia.
Um SGBD sério entrega três garantias mínimas. A primeira é a persistência: o dado sobrevive a reinicializações. A segunda é o controle de concorrência, que impede duas transações simultâneas de corromper o estado. A terceira é a durabilidade, ou seja, uma escrita confirmada não se perde nem com crash.
Modelos e produtos diferentes escolhem caminhos diferentes para entregar cada uma dessas garantias e é aí que a arquitetura interna começa a importar.
Arquitetura interna de um SGBD: o caminho de uma query
Quando uma aplicação envia SELECT nome FROM clientes WHERE id = 42, essa string passa por seis estágios dentro do SGBD. Só depois disso vira uma resposta. Entender esse pipeline é o que separa quem usa banco de quem opera banco com autoridade.
- Parser. Valida a sintaxe, resolve identificadores contra o catálogo de metadados (a tabela
clientesexiste? a colunanomeexiste?) e produz uma árvore de análise. Se a query é malformada ou referencia objeto inexistente, o erro nasce aqui. - Otimizador, também chamado de query planner. Ele recebe a árvore do parser e gera vários planos de execução equivalentes em resultado mas diferentes em custo. Custo aqui é estimativa, calculada sobre estatísticas de cardinalidade, seletividade de índices e tamanho das tabelas. Por fim, vence o plano de menor custo esperado.
- Executor. Percorre o plano como uma árvore de operadores (scan, filter, join, sort) e invoca o storage engine para cada leitura ou escrita.
- Buffer pool. Camada de cache em memória que mantém as páginas mais acessadas recentemente. Se a página está no buffer, a leitura é quase instantânea. Caso contrário, ocorre um cache miss e o storage engine busca em disco.
- Storage engine. Organiza os dados em páginas de tamanho fixo, tipicamente de 4 KB, 8 KB ou 16 KB. Mantém os índices que apontam para essas páginas e cuida da disposição física em disco. Além disso, cada SGBD tem o seu: InnoDB no MySQL, heap mais btree no PostgreSQL, LSM-tree em bases como RocksDB e Cassandra.
- WAL (write-ahead log), também conhecido como redo log. O SGBD registra toda escrita sequencialmente no WAL antes de aplicá-la às páginas de dados. Esse passo permite a recuperação após crash: no restart, o banco relê o WAL a partir do último checkpoint e reaplica as transações confirmadas.
Esse pipeline tem reflexos operacionais diretos. Um buffer pool com hit ratio baixo significa leitura constante em disco. Um plano de execução ruim aparece como query lenta no log. Um WAL saturado gera backpressure em escritas. Por isso a observabilidade aplicada a bancos de dados olha para esses sinais internos e não só para o tempo total da query.
Buffer pool: o custo real de um cache miss
Para sair da teoria, subimos PostgreSQL 18.6 e MySQL 8.4.7 em container no dia 3 de setembro de 2026. O primário ficou com shared_buffers de 128 MB e uma tabela de 1 milhão de pedidos. Em seguida, a mesma consulta rodou três vezes, sendo a primeira logo após o restart, com o buffer vazio.
Na primeira execução o banco buscou 7.909 páginas fora do buffer pool e esperou 37,8 ms por disco. Nas duas seguintes, por outro lado, as mesmas 7.953 páginas vieram todas da memória e a espera por I/O caiu a zero.
O número que o banco exibe, porém, engana. No MySQL 8.4.7 com os mesmos 128 MB, o hit ratio subiu de 90,56% para 93,96% ao longo de quatro consultas repetidas. Ou seja, o servidor não fez uma única leitura nova em disco: os 1.994 acessos físicos ficaram parados e só o denominador cresceu.
Por isso o sinal que serve de alerta é a variação entre duas amostras, nunca o valor absoluto acumulado desde o último boot. Um servidor com meses no ar exibe hit ratio alto mesmo quando o workload da última hora está lendo disco sem parar.
Além disso, a documentação do InnoDB registra que servidores dedicados costumam destinar até 80% da memória física ao buffer pool. A partir daí, a decisão vira quanto do dado quente cabe na memória.
Checkpoint: o número que assusta e o número que trava
O checkpoint é o momento em que o SGBD despeja as páginas sujas do buffer pool no disco. Ao mesmo tempo, ele marca até onde o WAL já foi aplicado. No mesmo laboratório, com checkpoint_timeout de 60 segundos, quatro checkpoints seguidos gastaram entre 53,4 e 53,9 segundos de escrita.
Cada fsync, porém, levou de 27 a 46 milissegundos. A diferença entre os dois números é o que importa na prática.
Espalhar a escrita é intencional. O SGBD a distribui ao longo de 90% do intervalo, conforme o checkpoint_completion_target, para não criar pico de I/O. Quem pode travar o banco é o fsync, portanto alertar sobre o tempo de escrita gera falso positivo garantido.
Modelos de dados: como cada família organiza a informação
O SGBD é o motor. O modelo de dados é a gramática que ele impõe sobre a informação. A escolha do modelo define o que é fácil e o que é caro fazer depois. Cinco famílias dominam a prática atual.
Modelo relacional
Organiza dados em tabelas com colunas tipadas e relaciona registros via chaves primárias e estrangeiras. É o padrão desde os anos 1970 porque SQL resolve bem consultas declarativas arbitrárias. PostgreSQL, MySQL, Oracle e SQL Server são os exemplos canônicos. Nesse sentido, vale o guia sobre o SGBD MySQL para aprofundar em um representante específico.
Modelo documento
Armazena registros semiestruturados (JSON ou BSON) com esquema flexível por documento. Ou seja, cada registro carrega sua própria estrutura. MongoDB e CouchDB são os exemplos.
Serve bem quando o esquema muda com frequência ou quando o agregado é naturalmente hierárquico, como um pedido com seus itens aninhados. Para cenários de ingestão bruta em larga escala, o modelo também é a base de muitos data lakes.
Modelo chave-valor
É o mais simples dos cinco: uma chave aponta para um blob opaco. Leitura e escrita são O(1) por chave e não existe consulta por atributo. Redis e DynamoDB são os exemplos. Serve, portanto, para cache, sessões, contadores e qualquer coisa com padrão de acesso por identificador único.
Modelo grafo
Representa entidades como vértices e relacionamentos como arestas, ambos com atributos. Consultas percorrem caminhos em vez de fazer joins. Neo4j é o exemplo mais conhecido. Serve para recomendação, detecção de fraude e qualquer domínio em que o relacionamento em si é o dado principal.
Modelo colunar
Armazena por coluna em vez de por linha. Leituras analíticas que agregam uma coluna inteira em bilhões de registros ficam muito mais rápidas. O ganho chega a duas ordens de grandeza sobre o modelo relacional orientado a linha. ClickHouse, BigQuery e Redshift são os exemplos. Por isso é a base de grande parte dos data warehouses modernos.
Cada modelo resolve bem um conjunto de padrões de acesso e mal os demais. Se o objetivo é comparar produtos específicos e escolher um para um projeto, vale outro caminho. O guia comparativo dos principais bancos de dados traz a análise produto a produto. Este artigo segue no plano arquitetural, para explicar por que cada modelo se comporta como se comporta.
ACID, BASE e níveis de isolamento: as garantias transacionais
Toda escrita minimamente importante é embrulhada em transação: um bloco de operações que deve ser aplicado por inteiro ou não ser aplicado de forma alguma. O modelo clássico para raciocinar sobre transações é ACID, acrônimo formado por quatro propriedades.
Atomicidade garante que todas as operações da transação aparecem como uma unidade indivisível. Consistência garante que o banco passa de um estado válido para outro estado válido conforme as regras de integridade. Isolamento controla como transações concorrentes enxergam umas às outras. Durabilidade garante que o commit sobrevive a falhas de sistema.
Bancos distribuídos que priorizam disponibilidade sobre consistência estrita adotam o modelo BASE: basicamente disponível, estado mole e consistência eventual. Em vez de rejeitar escritas quando nós estão inacessíveis, eles aceitam e reconciliam depois. Dynamo, Cassandra e muitos sistemas NoSQL se encaixam nesse perfil.
A documentação oficial do PostgreSQL detalha o modelo MVCC que o Postgres usa para implementar isolamento sem bloquear leituras com escritas.
Dentro de ACID, o isolamento é a propriedade mais escorregadia na prática. O padrão ANSI SQL define quatro níveis, cada um impedindo um subconjunto de anomalias:
| Nível de isolamento | Dirty read | Non-repeatable read | Phantom read |
|---|---|---|---|
| Read uncommitted | Possível | Possível | Possível |
| Read committed | Impossível | Possível | Possível |
| Repeatable read | Impossível | Impossível | Possível |
| Serializable | Impossível | Impossível | Impossível |
Dirty read é ler dado de transação ainda não confirmada. Non-repeatable read é ler o mesmo registro duas vezes na mesma transação e obter valores diferentes. Phantom read é reexecutar uma consulta de faixa e ver registros novos que não existiam antes.
Subir o nível de isolamento elimina anomalias mas aumenta contenção e reduz throughput, portanto a escolha é trade-off e não default universal.
O que o nível padrão deixa passar
A tabela acima é teoria conhecida. No entanto, a surpresa aparece ao descobrir qual nível o seu banco usa quando ninguém declara nada. Duas sessões concorrentes no PostgreSQL 18.6 mostram o efeito. A sessão A lê o mesmo registro duas vezes, enquanto a sessão B confirma uma alteração no meio.
No nível padrão do PostgreSQL, a mesma leitura devolveu 100,00 e depois 999,00 dentro da mesma transação. Por outro lado, subir para REPEATABLE READ congela a visão e as duas leituras voltam iguais.
Esse congelamento, porém, tem preço. Quando a transação também tenta escrever no registro alterado, o banco aborta com could not serialize access due to concurrent update.
Essa é a armadilha de quem troca de banco. O PostgreSQL 18.6 entrega read committed por padrão, enquanto o MySQL 8.4.7 entrega REPEATABLE READ. Ou seja, a mesma aplicação, com o mesmo código, permite anomalias diferentes em cada um.
Portanto, quem sobe de nível precisa tratar o erro de serialização e repetir a transação. Ignorar isso troca uma anomalia silenciosa por uma exceção em produção.
Indexação: B-tree, hash e bitmap
Sem índice, toda consulta que filtra por atributo precisa fazer full scan: ler a tabela inteira linha a linha. Em tabelas de milhões de registros, isso é inviável. O índice é uma estrutura auxiliar que organiza valores de uma ou mais colunas de forma que o lookup seja sub-linear.
O B-tree é a estrutura de índice mais comum. É uma árvore balanceada em que cada nó contém várias chaves ordenadas. A busca desce pela árvore até a folha que aponta para o registro. Custo de busca é O(log n).
Serve bem para consultas de igualdade (WHERE id = 42) e de faixa (WHERE data BETWEEN ... AND ...) e é o padrão no PostgreSQL, MySQL e Oracle.
Quem trabalha com planos de execução lentos sabe onde está boa parte do trabalho de otimização: garantir que o banco escolha o B-tree certo. O guia de otimização de performance no PostgreSQL trata o assunto em profundidade.
O hash mapeia cada chave a um bucket via função de hash. Busca por igualdade é O(1) no caso médio, mais rápida que B-tree. O custo é que não serve para consultas de faixa (o hash destrói a ordem das chaves) e sofre com alta colisão.
É a estrutura natural para chaves-valor puros como Redis e para índices específicos em bancos relacionais quando o padrão de acesso é exclusivamente por igualdade.
O bitmap representa cada valor possível da coluna como um vetor de bits em que cada bit corresponde a um registro. Colunas com baixa cardinalidade (sexo, estado civil, região) viram bitmaps compactos que respondem consultas com operadores booleanos eficientes (AND, OR).
Serve bem para data warehouses e cargas analíticas. Mal para OLTP com escritas frequentes, porque toda atualização precisa recalcular vários bitmaps.
A escolha de qual índice criar é decisão de design. Índices aceleram leitura mas custam espaço e tornam escritas mais lentas, porque cada INSERT ou UPDATE precisa atualizar todos os índices da tabela. Bancos bem-afinados têm índices deliberadamente escolhidos, não acumulados.
Replicação e alta disponibilidade
Um único nó de banco é ponto único de falha. Replicação é a técnica de manter cópias do dado em nós adicionais, para sobreviver à queda de um deles. Em muitos casos, serve também para distribuir carga de leitura.
O modelo mais comum é primário-réplica: um nó aceita escritas e propaga o WAL para um ou mais nós secundários que aplicam as mesmas mudanças. Na replicação síncrona, o primário só confirma o commit depois que a réplica confirmou a recepção. Já na assíncrona, ele confirma imediatamente e a réplica fica eventualmente em dia.
A escolha entre síncrono e assíncrono é trade-off direto entre RPO e latência de escrita. O RPO (recovery point objective) mede quanto dado já aceito se perde em caso de falha. Replicação síncrona zera o RPO mas paga em latência adicional em cada commit. Assíncrona mantém a latência baixa mas expõe uma janela de replication lag em que escritas aceitas ainda não estão replicadas.
O preço da replicação síncrona, medido
Esse trade-off costuma ser descrito sem número. No laboratório, um primário PostgreSQL 18.6 com uma réplica em streaming recebeu 45 segundos de carga de escrita com quatro clientes concorrentes. Além disso, o mesmo teste rodou duas vezes em cada modo.
A réplica assíncrona ficou em média 9,5 KB atrás do primário, com atraso de replicação abaixo de 8 milissegundos. Ligar o modo síncrono zera essa janela. No entanto, o pedágio medido foi de 25% a mais de latência por commit e cerca de 20% menos transações por segundo.
O critério de decisão sai daí. Quando a janela de perda aceitável do negócio é maior que alguns milissegundos, a assíncrona entrega mais throughput no mesmo hardware. Em contrapartida, se nenhuma transação confirmada pode se perder, a síncrona é o caminho e o plano de capacidade precisa absorver o pedágio.
Arquiteturas multi-primário (como Cassandra e a maioria dos bancos em estilo Dynamo) aceitam escritas em qualquer nó e usam protocolos de reconciliação baseados em quórum. Eles trocam consistência estrita por disponibilidade diante de partição de rede, conforme o teorema CAP. Para quem quer entender os protocolos por trás, a especificação do protocolo Raft é referência obrigatória.
Alta disponibilidade depende também de failover: o processo automático ou assistido de promover uma réplica a primário quando o primário original falha.
Failover mal-configurado causa dois problemas clássicos: split-brain (dois primários aceitando escritas em paralelo) e perda de dados na janela de replication lag. É por isso que monitorar o banco de dados é pré-requisito para qualquer operação séria. A visibilidade precisa ser contínua sobre o lag, a posição do WAL e o estado de replicação.
Normalização vs desnormalização
Normalização é o processo de eliminar redundância em um esquema relacional aplicando formas normais sucessivas. A primeira forma normal (1FN) exige atomicidade dos valores (nenhum campo carrega lista). A segunda (2FN) elimina dependências parciais em chaves compostas. A terceira (3FN) elimina dependências transitivas.
Um esquema em 3FN tem cada fato em exatamente um lugar. Atualizações são baratas e consistentes porque não há duplicação. O custo é que consultas que precisam combinar informação passam a depender de joins. Joins entre tabelas grandes custam I/O e CPU.
Desnormalização é o movimento inverso: duplicar deliberadamente dados em várias tabelas ou em uma única tabela larga para evitar joins e acelerar leitura. O custo é escrita mais cara e risco de inconsistência, porque o mesmo fato precisa ser atualizado em múltiplos lugares.
Em OLTP (transactional, escritas frequentes, integridade crítica), normalização vence. Em OLAP (analytical, leituras massivas, agregações complexas), desnormalização vence.
Por isso data warehouses usam esquemas estrela ou floco de neve, com uma tabela fato central desnormalizada e dimensões ao redor. A decisão correta depende do workload, não de preferência estética.
Equipes que operam ambos os regimes em produção geralmente separam OLTP e OLAP fisicamente. Pipelines de engenharia de dados movem o dado do primeiro para o segundo, em lotes ou em streaming.
Quando usar cada modelo: guia de decisão
A pergunta prática que fecha o raciocínio arquitetural é: qual modelo serve a qual workload? A tabela abaixo organiza as escolhas típicas.
| Workload | Modelo recomendado | Motivo |
|---|---|---|
| Sistemas transacionais (ERP, CRM, bancário) | Relacional | ACID rigoroso, integridade referencial, consultas declarativas arbitrárias |
| APIs de conteúdo com esquema variável | Documento | Esquema flexível por registro, agregados hierárquicos naturais |
| Cache, sessões, contadores | Chave-valor | Acesso O(1) por chave, latência sub-milissegundo |
| Recomendação, rede social, antifraude | Grafo | Consulta por caminho substitui joins caros |
| Data warehouse, BI, agregações em bilhões de registros | Colunar | Varredura por coluna, compressão agressiva, scan analítico rápido |
| Telemetria e séries temporais | Time-series (variação de colunar) | Ingestão de alto volume, retenção por janela, downsampling automático |
Arquiteturas modernas raramente ficam em um único modelo. É comum ver OLTP relacional combinado com cache chave-valor e data warehouse colunar na mesma empresa.
A prática se chama polyglot persistence e exige observabilidade transversal para acompanhar o que acontece em cada banco sem precisar pular de console em console.
Monitore replicação, queries lentas e conexões antes que o banco vire gargalo.
Visibilidade contínua de PostgreSQL, MySQL, Oracle e SQL Server — com alertas de bloat, locks e degradação de performance integrados à sua operação de TI.
Conclusão
Tratar banco de dados como caixa preta funciona até certo ponto. O limite chega quando uma query lenta em produção, um lag de replicação ou um deadlock começa a custar dinheiro. O caminho para parar de operar no escuro tem três partes. A primeira é entender a arquitetura interna do SGBD. A segunda é reconhecer o modelo certo para cada workload.
Por fim, vem acompanhar as garantias transacionais como parâmetros conscientes, nunca como defaults invisíveis.
A boa notícia é que o mesmo conjunto de conceitos se aplica a PostgreSQL, MySQL, Oracle, MongoDB, Cassandra ou ClickHouse. Muda o produto, mas parser, otimizador, storage engine, isolamento, índice, WAL e replicação continuam sendo os pilares comuns. Dominar esses pilares é o que permite uma equipe escolher, afinar e monitorar qualquer banco com o mesmo rigor.
Se o próximo passo é traduzir essa arquitetura em visibilidade concreta sobre seus bancos críticos, fale com um especialista da OpServices. O monitoramento contínuo cobre replicação, planos de execução e saúde do storage engine de ponta a ponta.
Perguntas Frequentes
O que é um banco de dados?
Qual a diferença entre banco de dados e SGBD?
O que são propriedades ACID?
Como funciona a indexação em banco de dados?
INSERT ou UPDATE atualiza também os índices da tabela. A escolha correta é deliberada, baseada no padrão de acesso real.
