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-
- Int / BigInt, cujo incremento automático são chaves primárias boas o suficiente.
- Deve haver pelo menos 3 colunas que constituem a chave primária.
- 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?
algorithm
database-design
relational-database
primary-key
ddl
Perpetualcoder
fonte
fonte
PK(NEWID(),NEWID(),NEWID())
;-)Respostas:
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.
fonte
CHAR(1)
teria bastado, gosto desex
. Desnecessário dizer que foi um pesadelo trabalhar com ele.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.
fonte
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.
state
(CA, TX, NY), você também pode usar umachar(2)
chave natural em vez de um int.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.fonte
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.
fonte
Eu gosto do meu único.
fonte
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.
fonte
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.
fonte
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.
Para aumentar o desempenho das consultas que precisam localizar rapidamente um registro / linha específico na tabela.
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.
fonte
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.
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!
fonte
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. :-(
fonte
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!
fonte
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).
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).
fonte
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.
fonte
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.
fonte
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:
... e nenhuma razão sensata para não:
razões sensatas contra as quais ainda não pensei ou encontrei ainda são sempre bem-vindas ...
fonte
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.
fonte
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.
fonte
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.
fonte
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:
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 ...
fonte
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.
fonte
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"?
fonte
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 ??)
fonte
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.
fonte
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.
fonte
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.
fonte
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!).
fonte