Como você gosta de suas chaves primárias? [fechadas]


88

Em uma discussão bastante animada em minha equipe, fui levado a pensar no que a maioria das pessoas gosta como chaves primárias. Tínhamos os seguintes grupos-

  1. Int / BigInt, cujo incremento automático são chaves primárias boas o suficiente.
  2. Deve haver pelo menos 3 colunas que constituem a chave primária.
  3. Id, GUID e identificadores de linha legíveis por humanos devem ser tratados de forma diferente.

Qual é a melhor abordagem para PKs? Seria ótimo se você pudesse justificar sua opinião. Existe uma abordagem melhor que a acima?

EDIT: Alguém tem uma amostra / algoritmo simples para gerar identificadores legíveis por humanos para linhas que escalam bem?


1
Como isso é subjetivo, deve ser um wiki da comunidade
John Sheehan

2
"Deve haver pelo menos 3 colunas que constituem a chave primária"? O que isto significa? Você pode fornecer uma definição mais detalhada? Ou isso é parte do # 3?
S.Lott

@ S.Lott PK(NEWID(),NEWID(),NEWID());-)

@pst: Por que isso é um requisito? Por que deve haver três colunas em um PK? Por que um um ou quatro?
S.Lott

Pude ver um PK de três colunas parecido com ... LocalID (Incremento automático int), GlobalID (GUID), ForeignId (chave estrangeira como RolesType), etc. O LocalID + ForiegnId poderia ser uma combinação de chave composta. O Guid é usado para outros sites / serviços. Pessoalmente, eu não faria isso, apenas usaria o Guid + ForiegnId.
Jerad

Respostas:


76

Se for fazer qualquer sincronização entre bancos de dados com aplicativos ocasionalmente conectados, você deve usar GUIDs para suas chaves primárias. Depurar é um tanto chato, então, fora esse caso, tenho a tendência de me limitar a ints com incremento automático.

Ints de incremento automático devem ser o seu padrão e não usá-los deve ser justificado.


3
Não é necessário um GUID, basta alterar a etapa para 10 ou 20 ou quantos servidores você precisará para sincronizar no futuro.
Robert C. Barth

43
90% das vezes, pelo menos, um GUID não é necessário e desperdiça espaço.
Jonathan Leffler

8
Eu realmente acho que GUIDs é um exagero. Nunca precisei ter GUIDs como minhas chaves primárias.
Cyril Gupta

7
Ou, em vez de desperdiçar espaço e correr o risco de colisão com um GUID, faça uma chave composta da chave primária original e um pequeno identificador, onde o pequeno identificador é diferente para cada fonte de sincronização.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

5
Uma loja para a qual trabalhei usava GUIDs para tudo, mesmo quando identificadores públicos estavam disponíveis, como códigos ISO de país ou idioma. E mesmo quando um booleano ou CHAR(1)teria bastado, gosto de sex. Desnecessário dizer que foi um pesadelo trabalhar com ele.
Lumi

56

Não vejo uma resposta que aponte (o que considero) o ponto realmente fundamental - ou seja, que uma chave primária é o que garante que você não obterá duas entradas na tabela para a mesma entidade do mundo real (como modelado no banco de dados). Essa observação ajuda a estabelecer o que são boas e más escolhas para a chave primária.

Por exemplo, em uma tabela de códigos e nomes de estado (EUA), o nome ou o código pode ser a chave primária - eles constituem duas chaves candidatas diferentes, e uma delas (normalmente a mais curta - o código) é escolhida como a chave primária. Na teoria das dependências funcionais (e dependências de junção - 1NF a 5NF - são as chaves candidatas que são cruciais, e não uma chave primária.

Para um contra-exemplo, nomes humanos geralmente são uma escolha ruim para a chave primária. Existem muitas pessoas que atendem pelo nome de "John Smith" ou algum outro nome semelhante; mesmo levando em consideração os nomes do meio (lembre-se: nem todo mundo tem um - por exemplo, eu não), há muito espaço para duplicação. Conseqüentemente, as pessoas não usam nomes como chaves primárias. Eles inventam chaves artificiais, como o número da previdência social (SSN) ou número do funcionário, e as usam para designar o indivíduo.

Uma chave primária ideal é curta, única, memorável e natural. Dessas características, a exclusividade é obrigatória; o resto precisa ser flexível, dadas as restrições dos dados do mundo real.

Quando se trata de determinar a chave primária de uma determinada tabela, portanto, você deve olhar o que essa tabela representa. Qual conjunto ou conjuntos de valores de coluna na tabela identifica exclusivamente cada linha na tabela? Essas são as chaves candidatas. Agora, se cada chave candidata consistir em 4 ou 5 colunas, então você pode decidir que elas são muito desajeitadas para fazer uma boa chave primária (principalmente por serem curtas). Nessas circunstâncias, você pode introduzir uma chave substituta - um número gerado artificialmente. Muitas vezes (mas nem sempre), um número inteiro simples de 32 bits é suficiente para a chave substituta. Em seguida, você designa essa chave substituta como a chave primária.

No entanto, você ainda deve garantir que as outras chaves candidatas (pois a chave substituta também é uma chave candidata, assim como a chave primária escolhida) são mantidas como identificador exclusivo - normalmente colocando uma restrição exclusiva nesses conjuntos de colunas.

Às vezes, as pessoas acham difícil identificar o que torna uma linha única, mas deveria haver algo para fazer isso, porque simplesmente repetir uma informação não a torna mais verdadeira. E se você não tiver cuidado e obtiver duas (ou mais) linhas que pretendem armazenar as mesmas informações e precisar atualizar as informações, existe o perigo (especialmente se você usar cursores) de atualizar apenas uma linha em vez de cada linha, então as linhas estão fora de sincronia e ninguém sabe qual linha contém as informações corretas.

Esta é uma visão bastante radical, em alguns aspectos.

Não tenho nenhum problema particular em usar um GUID quando necessário, mas eles tendem a ser grandes (como em 16-64 bytes) e são usados ​​com muita frequência. Muitas vezes, um valor de 4 bytes perfeitamente bom seria suficiente. Usar um GUID em que um valor de 4 bytes seria suficiente desperdiça espaço em disco e retarda até mesmo o acesso indexado aos dados, pois há menos valores por página de índice, então o índice será mais profundo e mais páginas terão que ser lidas para chegar ao em formação.


10
Em relação à sua amostra com nomes de estado dos EUA, eu preferiria uma chave substituta separada, simplesmente porque os códigos estão além do seu controle. Se eles mudarem por qualquer motivo, você terá um problema.
Dirk Vollmar

(continuação) Por exemplo, a Alemanha substituiu um sistema de código postal de 4 dígitos por um sistema de 5 dígitos na década de 1990, após a reunificação.
Dirk Vollmar

@divo: Eu sou um forte defensor das chaves artificiais / substitutas, mas mesmo eu não vejo a mudança do código postal de 4 para 5 dígitos como um bom exemplo. Os códigos postais geralmente não são usados ​​como chaves para nada. (Quando foi a última vez que você teve que consultar uma tabela PostalCode para descobrir algo sobre esse código? Não, ele é quase exclusivamente usado como parte de um endereço sem ser referenciado em nenhuma outra tabela. Eu diria que sua sugestão é quase igual a usar chaves substitutas para os próprios endereços.)
ErikE

@Emtucifor: Sim, talvez ZIP não seja um exemplo muito prático, mas meu ponto é que se parte de sua chave substituta está fora de seu controle e muda por qualquer motivo, você está em apuros. Pense em alguém criando um novo esquema de número de previdência social, um novo esquema de ISSN ou - talvez mais realista - uma empresa decidindo criar um novo sistema de identificação de produto após uma fusão, atribuindo novos números de funcionários a seus funcionários para ajustar seu crescimento etc. todos apenas exemplos fictícios, mas, como mostra meu exemplo anterior com o ZIP, às vezes um sistema bem estabelecido pode mudar.
Dirk Vollmar

2
Seu primeiro ponto está correto. Existe um nome para esta restrição. É chamado de "integridade da entidade". EI requer que cada entidade tenha uma identidade única. As chaves primárias geralmente atendem a esse requisito, exceto quando a numeração automática é usada. Com a numeração automática, você pode obter duas linhas idênticas, exceto para a numeração automática. Isso geralmente viola a integridade da entidade.
Walter Mitty,

26

Esta é apenas uma questão religiosa porque as pessoas buscam uma resposta correta universal. O fato de que sua equipe e este tópico de SO mostram tanto desacordo deve ser uma pista de que há boas razões para usar todas as soluções que você descreve, em diferentes circunstâncias.

  • As chaves substitutas são úteis quando nenhum outro atributo ou conjunto de atributos na tabela é adequado para identificar linhas de maneira exclusiva.
  • As chaves naturais são preferidas, quando possível, para tornar a tabela mais legível. As chaves naturais também permitem que a chave estrangeira em uma tabela dependente contenha um valor real em vez de um id substituto. Por exemplo, quando você precisa armazenar state(CA, TX, NY), você também pode usar uma char(2)chave natural em vez de um int.
  • Use chaves primárias compostas quando apropriado. Não adicione uma " id" chave substituta desnecessariamente quando existir uma chave composta perfeitamente boa (isto é especialmente verdadeiro em tabelas muitos-para-muitos). Um mandato para uma chave de três colunas em cada tabela é um absurdo absoluto.
  • GUIDs são uma solução quando você precisa preservar a exclusividade em vários sites. Eles também são úteis se você precisar que os valores na chave primária sejam exclusivos, mas não ordenados ou consecutivos.
  • INT vs. BIGINT: não é comum que uma tabela exija um intervalo de 64 bits para chaves primárias, mas com a disponibilidade crescente de hardware de 64 bits, isso não deve ser um fardo e oferece mais garantia de que você não irá estourar. O INT é obviamente menor, portanto, se o espaço for escasso, pode dar uma pequena vantagem.

6
Eu discordo tanto quanto uma pessoa pode fazer. Chaves naturais são horríveis. E se alguém quiser alterar os dados? Oh, você não pode. Escrever junções em teclas naturais compostas é uma dor. Carregar essa chave composta para todas as suas tabelas relacionadas é um desperdício.
Robert C. Barth

2
@Robert: leia sobre "ON UPDATE CASCADE". Mas eu entendo o que você está dizendo e concordo que é melhor usar uma chave substituta na maioria das vezes, porque os atributos estão sujeitos a alterações e não são únicos.
Bill Karwin

1
As chaves primárias devem ser imutáveis. As atualizações em cascata são apenas um hack feio para uma decisão de design ruim neste caso. Chaves naturais NUNCA são preferidas. O mesmo para as chaves compostas, que se espalham como uma praga. Qualquer pessoa com mais de 3 meses de experiência em desenvolvimento de banco de dados sabe disso.
FDCastel

7
@FD: Não concordo com sua afirmação inequívoca e venho desenvolvendo com bancos de dados SQL desde 1992. Mas certamente é verdade que as chaves substitutas são mais capazes de permanecer imutáveis.
Bill Karwin

20

Eu gosto do blog do The Database Programmer como uma fonte para esse tipo de informação.

3 colunas para uma chave primária? Eu diria que as colunas devem ter restrições exclusivas apropriadas conforme as regras de negócios exigem, mas ainda teria uma chave substituta separada. Chaves compostas significam que a lógica de negócios entra na chave. Se a lógica mudar, todo o seu esquema está ferrado.


2
Eles mudaram o link, aqui está o marcador atualizado: database-programmer.blogspot.com/2008/09/…
Bryan Rehbein

Acabei de herdar um projeto como este. E a primeira coisa que eles queriam fazer explodiu o esquema. Chaves substitutas FTW. Lógica de negócios em seu DB FTL.
Jason


11

Um pouco fora do assunto, mas sinto-me compelido a intervir com ...

Se sua chave primária for um GUID, não a torne um índice clusterizado . Como os GUIDs não são sequenciais, os dados serão reorganizados no disco durante quase todas as inserções. (Eca.) Se você estiver usando GUIDs como chaves primárias, eles devem ser índices não clusterizados.


1
Muito bom ponto - é preciso distinguir entre o conceito LÓGICO de uma chave primária (pode ser válido usar um GUID para isso, especialmente se a replicação estiver envolvida), e o conceito FÍSICO da chave de cluster - que NUNCA deve ser um GUID, pois isso leva à fragmentação excessiva do índice
marc_s

3
Na verdade, isso não é preciso. Os dados serão inseridos em ordem, o que, dada a natureza aleatória do GUID, pode acabar em qualquer lugar da tabela. Na chance remota de não haver espaço, uma divisão de página acontecerá, mas certamente não "reorganizando no disco durante cada inserção", nem mesmo perto.
Ralph Shillington

@Ralph, você está certo, não TODAS as inserções, mas o suficiente para causar um impacto de 20x no desempenho. sql-server-performance.com/articles/per/…
Portman

A função newsequentialid () do SQL Server resolve o problema de fragmentação do índice com GUIDs (embora 24 bytes ainda seja um pouco excessivo se você não precisar absolutamente de exclusividade global). Consulte msdn.microsoft.com/en-us/library/ms189786.aspx.
ErikE

10

Eu sempre vou com a chave substituta. Uma chave substituta (geralmente uma coluna de identidade, incremento automático ou GUID) é aquela em que a chave não está presente nos próprios dados. Uma chave natural, por outro lado, é aquela que, por si só, identifica exclusivamente a linha. Pelo que posso dizer na vida, dificilmente existem chaves naturais reais . Nem mesmo coisas como o SSN nos Estados Unidos são uma chave natural. As chaves primárias compostas são um desastre esperando para acontecer. Você não pode editar nenhum desses dados (que é a maior desvantagem de qualquer chave natural, composta ou não), mas o pior é que com uma chave composta, agora você tem que perpetuar esses dados chave em todas as tabelas relacionadas. Que desperdício gigante.

Agora, para a seleção da surrogate key, fico com as colunas de identidade (trabalho principalmente no MS SQL Server). Do GUID são muito grandes e Microsoft recomenda contra a usá-los como um PK. Se você tiver vários servidores, tudo o que você precisa fazer é aumentar em 10 ou 20 ou o que você achar que é o número máximo de servidores para os quais você precisará sincronizar / expandir, e apenas aumentar a semente para cada tabela em cada servidor subsequente , e você nunca terá uma colisão de dados.

É claro que, por causa do incremento, tornei a coluna de identidade um BigInt (também conhecido como long [64 bits]).

Fazendo um pouco de matemática, mesmo que você faça o incremento 100, você ainda pode ter 92.233.720.368.547.758 (> 92 quatrilhões) de linhas em sua tabela.


9

Acho que o uso da palavra "Primária" na frase "Chave Primária" é, em um sentido real, enganoso.

Primeiro, use a definição de que uma "chave" é um atributo ou conjunto de atributos que devem ser únicos na tabela,

Então, ter qualquer chave serve a vários propósitos frequentemente mutuamente inconsistentes.

  1. Para usar como condições de junção para um ou mais registros em tabelas filho que têm um relacionamento com esta tabela pai. (Definindo explícita ou implicitamente uma chave estrangeira nessas tabelas filho)
  2. (relacionado) Garantir que os registros filho devem ter um registro pai na guia pai; e (A tabela filho FK deve existir como chave na tabela pai)
  3. Para aumentar o desempenho das consultas que precisam localizar rapidamente um registro / linha específico na tabela.

  4. Para garantir a consistência dos dados, evitando que linhas duplicadas que representam a mesma entidade lógica sejam inseridas na tabela. (Isso geralmente é chamado de chave "natural" e deve consistir em atributos de tabela (entidade) que são relativamente invariáveis.)

Claramente, qualquer chave não significativa e não natural (como um GUID ou um inteiro gerado automaticamente é totalmente incapaz de satisfazer o nº 4.

Mas muitas vezes, com muitas (a maioria) tabelas, uma chave totalmente natural que pode fornecer # 4 muitas vezes consiste em vários atributos e é excessivamente ampla, ou tão ampla que usá-la para os fins # 1, # 2 ou # 3 causará inaceitáveis conseqüências de desempenho.

A resposta é simples. Use ambos. Use uma chave integral de geração automática simples para todos os Joins e FKs em outras tabelas filho, mas certifique-se de que cada tabela que requer consistência de dados (muito poucas tabelas não) tenha uma chave única natural alternativa que evitará inserções de linhas de dados inconsistentes. .. Além disso, se você sempre tiver os dois, todas as objeções contra o uso de uma chave natural (e se ela mudar? Eu tenho que mudar cada lugar que é referenciado como FK) se tornam discutíveis, já que você não a está usando para isso. .. Você está usando apenas na tabela onde é um PK, para evitar dados duplicados inconsistentes ...

Quanto aos GUIDs, tenha muito cuidado ao usá-los, pois o uso de guids em um índice pode prejudicar a fragmentação do índice. Os algoritmos mais comuns usados ​​para criá-los colocam a parte "aleatória" do guid nas posições de bits mais significativas ... Isso aumenta a necessidade de desfragmentação / reindexação de índice regular conforme novas linhas são adicionadas.


A função newsequentialid () do SQL Server resolve o problema de fragmentação do índice de GUIDs (embora 24 bytes ainda seja um pouco excessivo se você não precisar absolutamente de exclusividade global). Consulte msdn.microsoft.com/en-us/library/ms189786.aspx.
ErikE

opa, eu quis dizer 16 bytes.
ErikE

8

Uma coisa que você nunca deve fazer é usar uma chave inteligente. Essa é uma chave em que as informações sobre o registro são codificadas na própria chave e, eventualmente, irão morder você.

Trabalhei em um lugar, onde a chave primária era o ID da conta, que era uma combinação de letras e números. Não me lembro de nada específico, mas, por exemplo, aquelas contas que eram de um determinado tipo, estariam na faixa de 600, e de outro tipo, começariam com 400. Isso era ótimo, até que o cliente decidiu pedir os dois tipos de trabalho. Ou mudou o tipo de trabalho que eles fizeram.

Outro lugar, usava a localização na árvore como chave primária para registros. Portanto, haveria registros como o seguinte.

Cat1.subcatA.record1
Cat1.subcatA.record2
Cat1.subcatB.record1
Cat2.subcatA.record1

Claro, a primeira coisa que os clientes queriam era uma maneira de mover os itens na árvore. Todo o conjunto de software morreu antes que isso acontecesse.

Por favor, por favor, por favor, se você está escrevendo um código que devo manter, por favor, não use uma chave inteligente!


Eu concordo de todo o coração. Smartkeys = burro.
Robert C. Barth

2
Isso não significa que as teclas naturais sejam burras. Mas bom ponto.

4

Sou fã do incremento automático como chave primária. Eu sei no fundo do meu coração que isso é uma desculpa, mas torna muito fácil classificar os dados quando eles foram adicionados (ORDER BY ID DESC, por instância).

3 colunas soa terrivelmente difícil de analisar humanamente.

E essa é a compensação - quanto da capacidade relacional você precisa, versus tornar ESTA TABELA AQUI compreensível para um humano interrogando-a (versus o procedimento armazenado ou interface programática).

o incremento automático é para nós, humanos. :-(


4

Geralmente, depende.

Pessoalmente, gosto de ints de incremento automático.

Mas, uma coisa que posso dizer é que nunca confie em dados de outras fontes como sua chave. Eu juro, toda vez que faço isso, volta para me morder. Bem, nunca mais!


3

Deve haver pelo menos 3 colunas que constituem a chave primária.

Eu não entendo isso.

Você está falando de uma "chave natural", por exemplo, "nome e data de nascimento"? Uma chave natural pode ser ideal se existir, mas a maioria dos candidatos a uma chave natural não é única (várias pessoas com o mesmo nome) ou não é constante (alguém pode alterar seu nome).

Int / BigInt, cujo incremento automático são chaves primárias boas o suficiente.

Eu prefiro Guid. Um problema potencial com o incremento automático é que o valor (por exemplo, "id do pedido") é atribuído pela instância do banco de dados (por exemplo, pelo "banco de dados de vendas") ... o que não funcionará inteiramente (em vez disso, você começa a precisar de chaves compostas) se você sempre precisa mesclar dados criados por mais de uma instância de banco de dados (por exemplo, de vários escritórios de vendas, cada um com seu próprio banco de dados).


As chaves primárias precisam ser exclusivas, mas não precisam ser constantes. Portanto, as chaves estrangeiras são declaradas com "ON UPDATE CASCADE". Mas supor que as chaves primárias são constantes ajuda a simplificar muitos aplicativos. Este é um benefício das chaves substitutas.
Bill Karwin

3

RE GUID's

Cuidado se este vai ser um banco de dados realmente muito REALMENTE grande, com muita carga e acesso rápido.

Em meu último trabalho, onde tínhamos bancos de dados de 100 a 500 milhões de registros, nosso pessoal de banco de dados argumentou fortemente contra os GUIDs e por um número decimal de tamanho apropriado. Eles sentiram que (no Oracle) a diferença de tamanho no armazenamento interno para uma string Guid - vs - um valor decimal faria uma diferença muito perceptível nas pesquisas. (Chaves maiores = árvores mais profundas para atravessar)

A natureza aleatória dos GUIDs também reduz significativamente o fator de preenchimento das páginas de índice - isso aumenta drasticamente o tearing e a E / S do disco.


"Reduz o fator de preenchimento"? Não tenho certeza do que isso poderia significar O fator de preenchimento é um negócio único, definido como a porcentagem de espaço livre solicitado no nível folha do índice no momento em que o índice é construído. Os valores de GUID por sua distribuição de natureza aleatória ao longo da amplitude do nível de folha em inserções nesse espaço livre fornecido pelo fator de preenchimento.
Ralph Shillington,

1
Desde quando um GUID é uma string? Os GUIDs devem ser armazenados internamente como 16 bytes por qualquer DBMS respeitável. Armazenar como 32 bytes na representação hexadecimal seria injusto! (ou 36 com travessões ou 38 com chaves)
ErikE

2

Colunas de incremento automático. Consigo fazer meu código funcionar perfeitamente com SQL Server ou Oracle, um usando identidade e o outro usando sequências por meio de meu DAL, e não poderia estar mais feliz. Eu concordo, GUIDs às vezes são necessários se você estiver fazendo replicação ou enviando dados para recebê-los posteriormente após o processamento.


2

Sempre usei uma chave substituta - um inteiro de incremento automático chamado 'id'. Posso ver muitos motivos para fazer isso, mesmo quando outra opção é óbvia:

  • Consistência
  • Independente de dados (exclusivo, não destruído por alterações no formato)
  • Legível

... e nenhuma razão sensata para não:

  • Ambiguidade nas junções? - Aliasing tabelas é uma prática melhor, IMHO
  • Tabelas ótimas? - Remover um byte por entrada é uma otimização prematura, IMHO
  • Decisão por mesa? - Não é mais consistente
  • Problemas de dimensionamento? - Eh? Por quê?
  • Estrutura de dados hierárquica? - Isso é desnormalização, um outro assunto de religião. Basta dizer que sou um fã em algumas circunstâncias em teoria, mas nunca na prática :)

razões sensatas contra as quais ainda não pensei ou encontrei ainda são sempre bem-vindas ...


1

Este é um clássico "depende". Não existe uma resposta certa para cada projeto. Gosto de coisas diferentes para situações diferentes. Depende se estou usando um ORM e do que ele suporta. Depende da arquitetura geral (distribuída ou não, etc). Basta escolher um que você acha que funcionará e continuar discutindo sobre tabulações e espaços.


Ele ainda deseja saber COMO depende; somente com a consciência disso alguém pode vir a confiar em si mesmo para escolher ...
Nicholas Leonard

1

Costumo usar a opção nº 1 ou nº 3, dependendo do tamanho, do número de pessoas que se conectam e se é uma situação de vários servidores de banco de dados ou não.

A opção 2 não faz muito sentido para mim. Se qualquer um dos três não for suficiente para identificar um registro único, então é possível (sem passar por maquinações extras) que dois registros apareçam com os mesmos valores nas três colunas. Se você deseja impor exclusividade em qualquer combinação dos três, basta adicionar um índice para eles.


1

Só usei um int de incremento automático ou um GUID. 99% do tempo eu uso o int de incremento automático. É exatamente o que me ensinaram a usar quando aprendi sobre bancos de dados e nunca encontrei um motivo para não usá-los (embora eu conheça os motivos pelos quais um GUID seria melhor).

Eu gosto de ints de incremento automático porque ajuda na legibilidade. Por exemplo, posso dizer "dê uma olhada no registro 129383" e é muito fácil para alguém entrar e encontrá-lo. Com um GUID, isso é quase impossível de fazer.


2
Por que você diz isso? Parece que muitas pessoas usam um inteiro de incremento automático. Não pode ser tão ruim se funcionar e funcionar bem para o que você precisa.
dtc

1

Depois de uma resposta de definição básica, o que constitui uma boa chave primária é deixado em grande parte para a religião e os argumentos da sala de descanso. Se você tiver algo que é, e sempre será, mapeado exclusivamente para uma linha individual, funcionará bem como uma chave primária. Depois desse ponto, existem outras considerações:

  • A definição da chave primária não é excessivamente complexa? Isso evita a introdução de complexidade desnecessária para seguir uma "prática recomendada"?
  • Existe uma chave primária melhor possível que exigiria menos sobrecarga para o banco de dados manipular (ou seja, INTEGER vs. VARCHAR, etc)?
  • Estou ABSOLUTAMENTE certo de que a exclusividade e invariante de definição de minha chave primária não irão mudar?

Este último é provavelmente o que atrai a maioria das pessoas a usar coisas como GUIDs ou colunas inteiras de autoincremento, porque confiar em coisas como endereços, números de telefone, nomes / sobrenomes, etc, simplesmente não adianta. A única invariante sobre as pessoas em que consigo pensar são os SSNs, mas não tenho nem mesmo 100% de certeza sobre aqueles que permanecem exclusivos para sempre.

Espero que isso ajude a adicionar alguma clareza ...


Existem alguns casos históricos em que os SSNs não são únicos.
Bill Karwin

1

A maneira como abordo as chaves primárias (e acho que é a melhor) é evitar uma abordagem "padrão". Isso significa que, em vez de apenas colocar um número inteiro de autoincremento e chamá-lo de um dia, eu olho para o problema e digo "há uma coluna ou grupo de colunas que sempre será indefinido e não mudará?" Se a resposta for sim, eu adoto essa abordagem.


Isso significa que você 'evita o incremento automático de inteiros sempre que puder'? Meu entendimento era que os especialistas do setor achavam que o melhor desempenho em bancos de dados de grande escala vem de PKs de coluna única incrementais, indexados e com assinatura mínima.
Hardryv

1
Sempre pensei que os especialistas usassem a melhor ferramenta para o trabalho
Andrew G. Johnson

1

Quase sempre inteiros.

Eles têm outros bons motivos, além de serem menores / mais rápidos de processar. Qual você prefere escrever - "404040" ou "3463b5a2-a02b-4fd4-aa0f-1d3c0450026c"?


O último pode ser um número inteiro, com traços adicionados e na base 16. Mas sim, 404040 é mais rápido de processar do que o GUID longo. Então, novamente, 0 é ainda mais rápido de processar porque não requer um único bit de dados!
strager

1

Apenas um pouco relevante, mas uma coisa que comecei a fazer recentemente quando tenho pequenas tabelas de classificação (essencialmente aquelas que representariam ENUMs no código) é que vou tornar a chave primária um char (3) ou char (4). Em seguida, torno essas chaves primárias representativas do valor de pesquisa.

Por exemplo, tenho um sistema de cotação para nossos agentes de vendas internos. Temos "categorias de custo" em que cada item de linha de cotação é atribuído a um de ... Portanto, tenho uma tabela de pesquisa de tipo chamada 'tCostCategories', onde a chave primária é 'MTL', 'SVC', 'TRV', 'TAX', 'ODC'. Outras colunas na tabela de pesquisa armazenam mais detalhes, como os significados normais em inglês dos códigos, "Material", "Serviço", "Viagem", "Impostos", "Outros custos diretos" e assim por diante.

Isso é muito bom porque não usa mais espaço do que um int, e quando você está olhando os dados de origem, não precisa vincular a tabela de pesquisa para saber qual é o valor. Por exemplo, uma linha de citação pode ser semelhante a:

1 PartNumber $ 40 MTL
2 OtherPartNumber $ 29,99 SVC
3 PartNumber2 $ 150 TRV

É muito mais fácil usar um int para representar as categorias e, em seguida, vincular 1, 2, 3 em todas as linhas - você tem os dados bem à sua frente e o desempenho não parece afetado (não que eu ' eu realmente testei.)

No que diz respeito à verdadeira questão ... Eu gosto de identificadores únicos do RowGUID. Não estou 100% nisso, mas nem todas as linhas têm RowGuid interno? Nesse caso, usar o RowGuid na verdade ocuparia menos espaço do que ints (ou qualquer outra coisa). Tudo o que sei é que se for bom o suficiente para M $ usar no GreatPlains, é bom o suficiente para mim. (Devo me abaixar ??)


1

Ah, mais uma razão para usar GUIDs - eu uso uma estrutura de dados hierárquica. Ou seja, eu tenho uma tabela 'Empresa' e uma tabela 'Fornecedor' para as quais as chaves primárias correspondem. Mas também tenho uma tabela 'Fabricante' que também 'herda' da Empresa. Os campos que são comuns a fornecedores e fabricantes não aparecem nessas tabelas - eles aparecem na empresa. Nessa configuração, usar int's é muito mais doloroso do que Guids. No mínimo, você não pode usar chaves primárias de identidade.


1
Sim, você pode, simplesmente não faz com que as tabelas de subtipos tenham a propriedade de identidade, em vez disso, elas obtêm inserções explícitas do valor da tabela de supertipos. Consulte stackoverflow.com/questions/2112882/…
ErikE

1

Gosto de chaves naturais, sempre que posso confiar nelas. Estou disposto a pagar um pequeno preço de desempenho para usar chaves que façam sentido para os especialistas no assunto.

Para tabelas que descrevem entidades, deve haver uma chave natural simples que identifica instâncias individuais da mesma forma que as pessoas em questão. Se o assunto não tiver identificadores confiáveis ​​para uma das entidades, recorrerei a uma chave substituta.

Para tabelas que descrevem relacionamentos, eu uso uma chave composta, onde cada componente faz referência a uma entidade que participa do relacionamento e, portanto, uma linha em uma tabela de entidades. Novamente, o impacto no desempenho para usar uma chave composta é geralmente mínimo.

Como outros apontaram, o termo "chave primária" é um pouco enganador. No Modelo de Dados Relacional, o termo usado é "chaves candidatas". Pode haver várias chaves candidatas para uma única tabela. Logicamente, cada um é tão bom quanto o outro. Escolher um deles como "principal" e fazer todas as referências por meio dessa chave é simplesmente uma escolha que o designer pode fazer.


Descreva alguns exemplos de chaves naturais confiáveis.
ErikE

1
"confiável" não é propriedade de uma chave por si só. Em vez disso, tem a ver com a chave no contexto das pessoas que fornecem os dados. Se você está escrevendo um aplicativo para ser vendido a alguém que gerencia os dados, você deve adivinhar quais chaves serão confiáveis ​​para o cliente ou não. Dada a variedade de clientes, é quase certo que você errará em alguma fração de sua clientela.
Walter Mitty

Dito isso, aqui está um exemplo de uma chave na qual confiávamos há muito tempo. Tínhamos um banco de dados sobre cursos. Incluía livros didáticos e outros materiais de curso sobre cursos, ofertas de cursos programados, instrutores qualificados para ministrar cursos, pré-requisitos do curso, mensalidades e assim por diante. Quando o desenvolvimento do curso criou um novo curso, uma das primeiras coisas que fizeram foi atribuir um código de curso. Eles eram responsáveis ​​por garantir que os códigos dos cursos fossem exclusivos e que os cursos nunca mudassem seus códigos, uma vez atribuídos. Fazia parte dos dados que nos foram fornecidos.
Walter Mitty

Outro bom exemplo de chave natural confiável é o VIN (Vehicle Identification Number). Nos últimos anos, todo veículo vendido como novo possui um VIN anexado. Eles podem ser considerados únicos e imutáveis.
Walter Mitty

1

Guids.period.

No caso de você precisar expandir ou atribuir a chave primária por meios alternativos, eles serão seus amigos. Você pode adicionar índices para todo o resto.


atualização para esclarecer minha declaração.

Trabalhei em muitos tipos de sites diferentes. De pequenos negócios com um único servidor a grandes com vários servidores de banco de dados e da web. Certamente há aplicativos que não teriam problemas com o incremento automático de ints como chaves primárias. No entanto, eles não se enquadram no modelo de como faço as coisas.

Ao usar um GUID, você pode gerar o ID em qualquer lugar. Ele pode ser gerado por um servidor remoto, seu aplicativo da web, dentro do próprio banco de dados ou mesmo dentro de vários bancos de dados em uma situação de vários mestres.

Por outro lado, um INT incrementado automaticamente só pode ser gerado com segurança no banco de dados primário. Novamente, isso pode ser bom se você tiver um aplicativo que estará intimamente ligado a esse servidor de banco de dados de apoio e escalar horizontalmente não é algo com que você esteja preocupado.

Claro, o uso de GUIDs significa que você precisa ter processos de reindexação todas as noites. No entanto, se você estiver usando algo diferente de um INT incrementado automaticamente, você deve fazer isso de qualquer maneira. Caramba, mesmo com um INT como o principal, é provável que você tenha outros índices que precisam ser regenerados para lidar com a fragmentação. Portanto, o uso de GUIDs não adiciona exatamente outro problema porque essas tarefas precisam ser executadas de qualquer maneira.

Se você der uma olhada nos aplicativos maiores por aí, notará algo importante: todos eles usam GUIDs codificados em Base64 como chaves. A razão para isso é simples, o uso de GUIDs permite dimensionar fora facilmente Considerando que não pode haver um monte de aros para saltar através de ao tentar escalar INTs.

Nosso aplicativo mais recente passa por um período de inserções pesadas que dura cerca de um mês. Depois disso, mais de 90% das consultas são todas selecionadas para relatórios. Para aumentar a capacidade, posso trazer servidores de banco de dados adicionais durante este grande período de inserção; e depois mesclá-los facilmente em um único banco de dados para relatórios. Tentar fazer isso com INTs seria um pesadelo absoluto.

Francamente, sempre que você agrupar um banco de dados ou configurar a replicação, o servidor de banco de dados exigirá que você tenha GUIDs na mesa de qualquer maneira. Portanto, se você acha que seu sistema pode precisar crescer, escolha aquele que é bom.


Você já examinou o fator de preenchimento de seus índices? A natureza aleatória dos GUIDs faz deles queijo suíço - reduzindo drasticamente sua eficácia.
stephbu

2
"Guids.period": Isso é tão errado. GUIDs devem ser usados ​​quando apropriado. Como o outro comentador apontou, pode tornar a vida de um programador fácil, mas afeta o tamanho geral e o desempenho do banco de dados.
Mitch Wheat

No final do dia, posso dimensionar meus aplicativos em vários servidores de banco de dados sem problemas. Mas acho que vocês trabalham em sites pequenos.
NotMe

3
GUID pode ser bom para a chave primária lógica, mas NUNCA NUNCA use uma coluna GUID como sua chave CLUSTERING - você se afogará na fragmentação do índice levando a um desempenho POBRE .....
marc_s

Eu certamente não proclamaria "Guids.period." sobre esse assunto - na verdade, mesmo em uma indústria tão repleta de 'melhores práticas', esse tipo de declaração o coloca em terreno instável por padrão (especialmente com essa declaração). Qualquer coisa tão dolorosa de se lidar quanto um GUID precisa de uma justificativa difícil e, como JL diz, acho que a maioria de nós consideraria isso um último recurso. É como se você postasse sem ler o resto do tópico.
Hardryv

0

Este é um assunto complexo, quer você tenha percebido ou não. Pode cair na seção deste FAQ StackOverflow.

Que tipo de perguntas não devo fazer aqui?

Evite fazer perguntas subjetivas, argumentativas ou que exijam uma discussão extensa. Este é um lugar para perguntas que podem ser respondidas!

Isso tem sido debatido por anos e continuará a ser debatido por anos. As únicas dicas de consenso que tenho visto são que as respostas são um tanto previsíveis, dependendo se você está perguntando se você está perguntando a um cara OO (GUIDs são a única maneira de ir!), Um modelador de dados (as chaves naturais são a única maneira de ir!), ou um DBA voltado para o desempenho (INTs são o único caminho a percorrer!).


Não vou deixar a discussão se prolongar. Eu estava curioso para ver o consenso geral.
Perpetualcoder

1
Eu digo fazer todas as perguntas que desejar! Caso contrário, esta comunidade se tornará estática e supercontrolada como a wikipedia parece ter se tornado. Parece-me que às vezes você precisa deixar as pessoas perguntarem o que quiserem. Confie neles, e eles podem vir a confiar em si mesmos!
Nicholas Leonard
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.