terça-feira, 6 de novembro de 2012

Chave Primária - "Natural" ou "Surrogate" ?

Sempre que se inicia a modelagem de um sistema, existe (ou pelo menos deveria existir) uma discussão sobre a questão das chaves primárias, baseada na seguinte pergunta: Devemos usar campos com significado de negócio - "Natural Keys" (RG, CPF, Matrícula, Apólice) ou números gerados artificialmente, sem significado fora do sistema - "Surrogate Keys" ?

Já trabalhei com sistemas nas duas abordagens e hoje defendo a segunda opção: chaves artificiais, sem relação alguma com o negócio; apresento aqui os prós e contras que me levaram a essa decisão.

Prós:
  • Chaves artificiais permitem alterações de negócio com menos impacto. Este é provavelmente o argumento mais importante. Chaves naturais estão sempre sujeitas a mudanças. Empresas se fundem, o governo adiciona mais um dígito, a lei muda. Sempre desconfie de um analista que diz que "esse campo não vai mudar nunca". Eu já tive que alterar uma informação (número de apólice) que era PK de uma tabela de 600 mil registros, com mais de 100 "descendentes" distribuídos em 11 níveis de dependência. Acredite, não é legal. Ou você acha impossível que amanhã ou depois o governo brasileiro resolva adicionar um dígito ou dois ao CPF ?
  • Chaves artificiais resultam em menos colunas nas tabelas. A opção das chaves naturais vem sempre acompanhada do uso de chaves compostas, o que leva à redundância da informação e ao desperdício de espaço.
  • Não ocorre o problema das FKs inúteis. Como não há chaves compostas, não existe a possibilidade de um dos campos ser NULL e outro não.
  • Não ocorrem updates nos campos da chave primária, portanto há menos chance de locks problemáticos. Aliás, updates em campos de chave primária violam o modelo relacional bom senso e não deveriam mesmo acontecer em hipótese alguma.
  • Como as chaves são de apenas um campo, e este campo é NUMBER, os joins são mais simples (para o desenvolvedor e para o otimizador) e mais rápidos.
  • O uso de chaves com apenas uma coluna facilita os cálculos para o otimizador de custo (que só sabe mesmo lidar com seletividade de múltiplas colunas no Oracle 11g release 2). Isso resulta em melhores decisões de planos de execução e portanto em melhor desempenho do sistema como um todo.
Contras:
  • Mais operações de join são necessárias para montar a informação para o usuário final. Isso pode ser resolvido de várias maneiras, sendo que "snapshots" ou "materialized views" são a opção mais popular hoje em dia.
  • Uma constraint a mais é necessária (do tipo "unique" nos campos da chave natural). 
  • Parte da integridade de negócio deixa de ser validada pelas FKs. Este é o maior ponto de atenção, pois o banco de dados não detectará anomalias como "pedido de um cliente com itens de outro cliente". Na prática, é difícil uma aplicação estável criar esse tipo de registro, mas processos de carga e migração podem fazê-lo facilmente. 

Veja Também:

4 comentários:

  1. Esse realmente é um assunto interessante. No caso de Pk Surrogate, não tem um problema também de documentação: Olha ai, Fulano, o 32043824093284 não é pra mudar, maldito.

    ResponderExcluir
  2. Parabéns pelo post, cara.

    Esse realmente é um assunto que está sempre surgindo no desenvolvimento de sistemas, daquele tipo de debate polarizado com árduos defensores em ambos os lados, e você conseguiu colocar muita luz sobre a questão. :-)

    Minha opinião nesse caso é a mesma para todos os outros exemplos desse tipo de debate: vai depender da situação, pois não existe solução perfeita para todos os casos (não existe bala de prata ou Santo Graal!). Se existisse, não seria necessário seres humanos para projetar e desenvolver sistemas, nós já teríamos automatizado isso!

    Nesse caso específico, por exemplo: você acha que a solução das views materializadas vai ser viável em bancos com milhões de registros com dados espalhados em diversas tabelas? Acredito a quantidade de registros pode tornar essa solução inviável. Qual a sua experiência nesse tipo de situação?

    Outro fator que pode influenciar é que às vezes temos bancos que suportam simultaneamente aplicações OO e aplicativos legados, desenvolvidos em linguagens procedurais, que não têm as facilidades das linguagens OO para lidar com chaves artificiais.

    Abraço!

    ResponderExcluir
  3. Obrigado :-)

    Sobre as views materializadas, o que eu posso dizer é que elas só funcionam bem com tabelas gigantes se você tiver consultas muito simples. Se a view for um pouco mais complexa, adeus: qualquer refresh será um refresh FULL e levará uma eternidade. Eu particularmente prefiro usar bons filtros, fazer os joins necessários e esperar pelo melhor. Se o otimizador não fizer o melhor, tuning nele. Hoje em dia trabalho com um sistema que faz isso pra todo lado em tabelas de centenas de milhões de registros e está tudo sob controle.

    ResponderExcluir
  4. Segue o registro do meu momento de grande decepção com o uso de views materializadas :)

    http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:15695764787749#3228518400346774818

    ResponderExcluir