Talvez a normalização não seja normal

Um dos itens com os quais estamos lutando agora na Stack Overflow é como manter níveis de desempenho quase instantâneos em um banco de dados relacional à medida que a quantidade de dados aumenta. Mais especificamente, como dimensionar nosso sistema de marcação. Os princípios tradicionais de projeto de banco de dados dizem que bancos de dados bem projetados são sempre normalizados, mas não tenho tanta certeza.

Dare Obasanjo fez uma excelente postagem Quando não normalizar seu banco de dados SQL em que ele fornece um exemplo de esquema de banco de dados para um site genérico de rede social. Veja como ele seria se o projetássemos da forma normalizada aceita:

exemplo de banco de dados de rede social, normalizado

A normalização certamente é eficaz em termos de limitação de duplicação. Cada entidade é representada uma vez, e somente uma vez, de modo que quase não há risco de inconsistências nos dados. Mas esse design também exige uma enorme seis junções para recuperar as informações de um único usuário.

select * from Users u
inner join UserPhoneNumbers upn
on u.user_id = upn.user_id
inner join UserScreenNames usn
on u.user_id = usn.user_id
inner join UserAffiliations ua
on u.user_id = ua.user_id
inner join Affiliations a
on a.affiliation_id = ua.affiliation_id
inner join UserWorkHistory uwh
on u.user_id = uwh.user_id
inner join Affiliations wa
on uwh.affiliation_id = wa.affiliation_id

(Atualizar: essa não é uma consulta real; ela está aqui apenas para ilustrar visualmente o fato de que o senhor precisa de seis uniões (ou seis consultas individuais, se preferir) para obter todas as informações sobre o usuário).

Essas seis junções também não estão ajudando em nada o desempenho do seu sistema. A normalização completa não é apenas difícil de entender e de trabalhar, ela também pode ser bastante lenta.

Como Dare aponta, a solução óbvia é desnormalizar — para recolher muitos dados em uma única tabela de usuários.

Exemplo de banco de dados social, desnormalizado

Isso funciona: as consultas agora são incrivelmente simples (select * from users) e, provavelmente, muito rápidas também. Mas o senhor terá um monte de buracos em branco nos seus dados, além de uma série de matrizes de campo com nomes estranhos. E todos aqueles problemas incômodos de integridade de dados que o banco de dados costumava aplicar para o senhor? Agora, tudo isso é trabalho do senhor. Parabéns pelo seu rebaixamento!

Ambas as soluções têm seus prós e contras. Portanto, deixe-me fazer a pergunta ao senhor: o que é melhor: um banco de dados normalizado ou um banco de dados desnormalizado?

Pergunta capciosa! A resposta é que não importa! Até que o senhor tenha milhões e milhões de linhas de dados, é claro. Tudo é rápido para pequenos n. Até mesmo um PC modesto para os padrões atuais – digamos, uma caixa dual-core com 4 gigabytes de memória – proporcionará ao senhor um desempenho quase idêntico em ambos os casos para qualquer coisa que não seja o maior dos bancos de dados. Supondo que sua equipe possa escrever consultas razoavelmente bem ajustadas, é claro.

Não faltam histórias de guerra fascinantes sobre bancos de dados de empresas que se tornaram grandes. Preocupa-me que essas histórias de guerra tenham um tom implícito de “Perdi 90 quilos e o senhor também pode perder!”; por favor, assuma o aviso de isenção de responsabilidade do minúsculoasterisco os resultados podem não ser típicos está em pleno vigor ao lê-los. Aqui está uma série que Tim O’Reilly compilou:

Há também o Alta escalabilidade que tem seu próprio conjunto de histórias de guerra de bancos de dados:

Primeiro, uma verificação da realidade. É parcialmente um ato de arrogância imaginar seu aplicativo como o próximo Flickr, YouTube ou Twitter. Como Ted Dziuba disse com muita propriedade, A escalabilidade não é problema do senhor, mas sim fazer com que as pessoas se importem com isso. Portanto, no que se refere ao design do banco de dados, meça o desempenho, mas tente errar mais para o lado do design simples e sensato. Escolha o esquema de banco de dados que o senhor achar mais fácil de entender e trabalhar no dia a dia. Não é preciso ser tudo ou nada, como na imagem acima; o senhor pode desnormalizar parcialmente onde faz sentido fazê-lo e permanecer totalmente normalizado em outras áreas onde não faz.

Apesar das inúmeras evidências de que a normalização raramente é escalonada, acho que muitos engenheiros de software se apegam zelosamente à normalização total do banco de dados apenas por princípiomuito tempo depois de ter sido deixado de fazer sentido.

Durante o desenvolvimento da Cofax na Knight Ridder, tivemos um problema sério depois de adicionar nosso 17º jornal ao sistema. O desempenho não era mais o que costumava ser e havia momentos em que os serviços não respondiam.

Foi iniciado um projeto para resolver o problema, para procurar “a arma fumegante”. A ideia era que o banco de dados, por ser tão bem projetado como era, não poderia ser o problema, mesmo com nosso sintoma clássico sendo o rápido crescimento do número de conexões ao banco de dados logo antes de uma falha. Portanto, nos concentramos em otimizar a pilha de aplicativos.

Eu discordei e argumentei várias vezes que era o nosso banco de dados que precisava de atenção. Primeiro, precisávamos ajustar as consultas e os índices, e estar dispostos a, se necessário, pré-calcular os dados nas gravações e evitar junções, desenvolvendo um conjunto de tabelas desnormalizadas. Foi difícil para mim engolir essa pílula, pois eu era o designer original do banco de dados. No fim das contas, foi mais difícil para todos os outros! Os consultores foram chamados. Eles declararam que o design do banco de dados estava correto e que o problema devia ser o aplicativo.

Depois de dois meses em que a equipe promoveu várias versões pensadas para resolver o problema, sem sucesso, voltamos aos meus argumentos originais.

Pat Helland observa que as pessoas normalizam porque seus professores lhes disseram para fazê-lo. Sou um pouco mais pragmático; acho que o senhor deve normalizar quando o dados diz ao senhor para:

  1. A normalização faz sentido para a sua equipe.
  2. A normalização proporciona melhor desempenho. (O senhor está medindo automaticamente todas as consultas que passam pelo seu software, certo?)
  3. A normalização evita uma quantidade onerosa de duplicação ou evita o risco de problemas de sincronização aos quais o domínio do problema ou os usuários são particularmente sensíveis.
  4. A normalização permite que o senhor escreva consultas e códigos mais simples.

Nunca, jamais, o senhor deve normalizar um banco de dados por causa de um vago senso de dever para com o os fantasmas de Boyce-Codd. A normalização não é um pó de fada mágico que o senhor borrifa sobre o banco de dados para curar todos os males; ela geralmente cria tantos problemas quanto os resolve. Não tema o espectro da desnormalização. Os dados duplicados e os problemas de sincronização costumam ser exagerados e relativamente fáceis de contornar com cron jobs. Os discos e a memória são baratos e ficam mais baratos a cada nanossegundo. Meça o desempenho de seu sistema e decida por si mesmo o que funciona, livre de predisposições e preconceitos.

Como diz o velho ditado, normalize até doer, desnormalize até funcionar.