Quais são as vantagens e desvantagens de incrementar IDs vs. chaves de texto completo para designs de chaves estrangeiras?


8

Em muitos projetos de bancos de dados relacionais, existem campos que são referenciados em outras tabelas.

Por exemplo, considere uma tabela de usuário com um nome de usuário exclusivo e uma segunda tabela armazenando dados de endereço.

Um layout possível, que eu diria que é a abordagem comum, porque observei na maioria dos softwares, é usar IDs de incremento automático como este:

Table users
===========
userId int primary auto_increment
userName varchar unique

Table adressdata
==========
userId int references users.userId
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userId,adress_type))

É assim que eu costumava fazer e como eu o via na maioria dos casos.

Outra maneira seria:

Table users
===========
userName varchar primary

Table adressdata
==========
userName varchar references users.userName
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userName,adress_type))

Aqui também armazenamos o nome de usuário completo na tabela adressdata.

Para mim, isso tem as seguintes vantagens:

  • Você pode selecionar o nome de usuário imediatamente da tabela sem a necessidade de associá-lo a outra tabela. Neste exemplo, isso é do ponto de vista do aplicativo provavelmente não é tão relevante, mas é apenas um exemplo.

  • Pode ser mais fácil dimensionar o banco de dados em um ambiente de replicação mestre-mestre, porque não há conflitos de incremento automático.

Mas também as desvantagens:

  • Os requisitos de espaço para o índice e os dados (mas mais relevante provavelmente será o índice) no campo da segunda tabela são mais altos.
  • Uma alteração do nome de usuário precisaria se propagar para todas as tabelas, o que consome mais recursos do que apenas alterá-lo em uma tabela e deixar os IDs como estão.

Na minha opinião, é muito mais fácil trabalhar com campos de texto e não usar IDs de incremento, e as compensações são mínimas e na maioria dos aplicativos não são relevantes.

É claro que alguns objetos SÃO identificados com um número incremental por sua natureza (por exemplo, as postagens no fórum devem receber um ID incremental porque provavelmente não há outro campo exclusivo, como o título).

Mas antes de começar a projetar meus layouts de banco de dados de uma maneira completamente diferente, gostaria de saber se há coisas em que não pensei.

  • Existem práticas recomendadas?

  • Existem prós / contras que eu não pensei e cujo efeito pode surgir posteriormente em algum momento?

  • Como você projeta pessoalmente bancos de dados sobre os pontos acima e por quê?

Respostas:


3

Sugiro usar o ID e não o nome de usuário, porque se você começar a usar o nome de usuário como uma coluna de junção em várias tabelas, lembre-se de atualizar todos eles.

A chave estrangeira da userstabela se torna a chave primária da addressdatatabela e a chave primária deve permanecer estável. É uma boa prática não alterar os campos da chave primária. Uma chave primária deve existir quando o registro é criado e deve permanecer inalterada durante toda a vida útil do registro.

Se você quiser mais informações O grande debate sobre chave primária é um ótimo artigo.


2

Estou fortemente no campo "não use chaves naturais". Isso porque vi como é difícil no sistema quando eles são atualizados e praticamente todas as chaves naturais que envolvem nomes de qualquer pessoa são atualizadas.

Os bancos de dados são otimizados para usar junções. Sim, você pode salvar algumas junções usando chaves naturais, mas o desempenho é atingido quando você precisa atualizar 1.000.000 de registros porque um grupo de chaves naturais foi alterado (ou mesmo dependendo do que está acontecendo) pode ser um grande problema.

Eu usaria apenas chaves naturais sob duas condições:

  1. se for razoavelmente garantido que a chave não muda (pense nos números VIN de automóveis) e
  2. se ele nunca for reutilizado (até coisas únicas como números de telefone e e-mails não são candidatos a um PK porque são reutilizados quando alguém para de usá-los).

E é claro que muitas chaves naturais que deveriam ser únicas não são. Se você está preocupado com a replicação, pode usar GUIDs.


1

O artigo da Wikipedia sobre Surrogate key tem alguns bits interessantes espalhados:

  • " Atributos que identificam unicamente uma mudança de poder entidade, que pode invalidar a adequação das chaves naturais, compostas. " Por exemplo, restrições posteriores sobre nomes de usuário pode invalidar chaves existentes ao usar a chave natural user nameque tal não irá afectar uma chave sintético.
  • " Chaves substitutas não mudam enquanto a linha existe. " Portanto, você não precisa (manual ou automaticamente) em cascata as alterações de chave nas tabelas de referências.
  • " Os valores das chaves substitutas geradas não têm relação com o significado do mundo real dos dados mantidos em sequência. " Isso pode dificultar a auditoria.

Acredito que o leitor atento pode encontrar pontos adicionais a considerar.


Boa resposta. Muitas chaves naturais tendem a mudar. Isso os torna inadequados para chaves que podem ser referenciadas como uma chave estrangeira. Há muitas razões pelas quais é apropriado alterar o ID do usuário de um usuário.
BillThor

1

Vou postar a partir da minha experiência, que provavelmente será muito diferente do que vários DBAs podem sugerir. Sou orientado principalmente para a combinação de desempenho e capacidade de manutenção ao projetar bancos de dados para vários projetos.

Eu nunca usaria uma chave natural para chave primária. Especialmente se eu usar o MySQL / InnoDB. Ainda não vi nenhum benefício em usar uma chave natural, geralmente o que vejo são implicações no desempenho, se nada. Atrevi-me "nunca, nunca" apenas porque as chaves naturais costumavam criar problemas de desempenho para meus projetos. Substituto (inteiro) sempre foi uma escolha melhor. Alguns podem não concordar, mas vivemos em um mundo onde o desempenho desempenha um papel sobre a teoria.

Quando se trata de JOINs, não tento evitá-los a todo custo, mas tendem a otimizá-los. Tento abusar, tanto quanto possível, do índice clusterizado do InnoDB (chave primária). Se os JOINs forem executados via PKs, eles serão extremamente rápidos. Eu também tendem a evitar FKs onde eles não fazem sentido. Honestamente, eu não me importaria muito com a integridade dos dados quando se trata de vincular usuários e suas informações de endereço. Eu o aplicaria ao vincular faturas a itens para usuários. O uso excessivo de FKs é um exagero e um pesadelo para manter depois que você faz referência a tudo, pensando que é um ótimo design manter relações em todo o lugar. Em algum momento, as coisas precisam mudar e quando o MySQL começa a reclamar com o erro 150 constantemente, você só quer ir para casa.

Você também mencionou a replicação e evitou conflitos devido à natureza dos auto_increments. Eu tinha um projeto em que tínhamos uma quantidade de bancos de dados armazenando informações de vendas de produtos, a quantidade de bancos de dados era variável. Todos os dias, os bancos de dados eram replicados em um banco de dados "principal", usado para gerar relatórios. A maneira como evitei conflitos de PK foi criando uma chave primária composta de uma parte de auto_increment e outra parte INT que denotava o local de onde o registro veio. Dessa forma, eu conseguia rastrear de onde vinham as coisas e não perdi nada (os produtos tinham o mesmo ID, apenas o identificador de local foi alterado).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.