it-swarm-pt.tech

Substituto vs. chaves naturais / comerciais

Aqui vamos nós de novo, o velho argumento ainda surge ...

Seria melhor termos uma chave comercial como chave primária ou preferiríamos um ID substituto (ou seja, uma identidade do SQL Server) com uma restrição exclusiva no campo da chave comercial?

Por favor, forneça exemplos ou provas para apoiar sua teoria.

161
Manrico Corazzi

Ambos. Tome seu bolo e coma.

Lembre-se de que não há nada de especial em uma chave primária, exceto que ela é rotulada como tal. Não é nada além de uma restrição NOT NULL UNIQUE, e uma tabela pode ter mais de uma.

Se você usar uma chave substituta, ainda desejará uma chave comercial para garantir exclusividade de acordo com as regras comerciais.

89
Ted

Apenas algumas razões para usar chaves substitutas:

  1. Estabilidade: alterar uma chave devido a uma necessidade comercial ou natural afetará negativamente as tabelas relacionadas. As chaves substitutas raramente, se alguma vez, precisam ser alteradas porque não há significado vinculado ao valor.

  2. Convenção: permite que você tenha uma convenção de nomeação de coluna de Chave Primária padronizada, em vez de precisar pensar em como associar tabelas com vários nomes para suas PKs.

  3. Velocidade: Dependendo do valor e do tipo PK, uma chave substituta de um número inteiro pode ser menor, mais rápida para indexar e pesquisar.

112
Jay Shepherd

Parece que ninguém ainda disse algo em apoio a chaves não substitutas (hesito em dizer "naturais"). Então aqui vai ...

Uma desvantagem das chaves substitutas é que elas são sem sentido (citadas como vantagem por alguns, mas ...). Às vezes, isso obriga a associar muito mais tabelas à sua consulta do que realmente seria necessário. Comparar:

select sum(t.hours)
from timesheets t
where t.dept_code = 'HR'
and t.status = 'VALID'
and t.project_code = 'MYPROJECT'
and t.task = 'BUILD';

contra:

select sum(t.hours)
from timesheets t
     join departents d on d.dept_id = t.dept_id
     join timesheet_statuses s on s.status_id = t.status_id
     join projects p on p.project_id = t.project_id
     join tasks k on k.task_id = t.task_id
where d.dept_code = 'HR'
and s.status = 'VALID'
and p.project_code = 'MYPROJECT'
and k.task_code = 'BUILD';

A menos que alguém pense seriamente o seguinte é uma boa ideia ?:

select sum(t.hours)
from timesheets t
where t.dept_id = 34394
and t.status_id = 89    
and t.project_id = 1253
and t.task_id = 77;

"Mas" alguém dirá "o que acontece quando o código para MYPROJECT, VALID ou HR muda?" Para qual minha resposta seria: "por que você precisaria para alterá-lo?" Essas não são chaves "naturais" no sentido de que algum órgão externo vai legislar que a partir de agora 'VÁLIDO' deve ser recodificado como 'BOM'. Apenas uma pequena porcentagem de chaves "naturais" realmente se enquadra nessa categoria - SSN e CEP são os exemplos usuais. Eu definitivamente usaria uma chave numérica sem sentido para tabelas como Pessoa, Endereço - mas não para tudo , que por algum motivo a maioria das pessoas aqui parece defender.

Veja também: minha resposta para outra pergunta

67
Tony Andrews

As chaves substitutas (normalmente números inteiros) têm o valor agregado de tornar as relações da tabela mais rápidas e mais econômicas na velocidade de armazenamento e atualização (ainda melhor, chaves estrangeiras não precisam ser atualizadas ao usar chaves substitutas, em contraste com os campos das chaves comerciais, que mudam de vez em quando).

A chave primária de uma tabela deve ser usada para identificar exclusivamente a linha, principalmente para fins de junção. Tabela Pense em uma pessoa: os nomes podem mudar e não têm garantia de exclusividade.

Think Companies: você é uma empresa feliz da Merkin que faz negócios com outras empresas da Merkia. Você é esperto o suficiente para não usar o nome da empresa como chave primária; portanto, você usa o ID exclusivo da empresa do governo da Merkia em seus 10 caracteres alfanuméricos. Então a Merkia altera os IDs da empresa porque eles acharam que seria uma boa ideia. Tudo bem, você usa o recurso de atualizações em cascata do seu mecanismo de banco de dados, para uma alteração que não deve envolver você em primeiro lugar. Mais tarde, seus negócios se expandem e agora você trabalha com uma empresa na Freedonia. O ID da empresa freedoniana tem até 16 caracteres. Você precisa aumentar a chave primária de identificação da empresa (também os campos de chave estrangeira em Pedidos, Emissões, MoneyTransfers etc.), adicionando um campo País na chave primária (também nas chaves estrangeiras). Ai! Guerra civil na Freedonia, está dividida em três países. O nome do país do seu associado deve ser alterado para o novo; atualizações em cascata para o resgate. BTW, qual é a sua chave primária? (País, Código da empresa) ou (Código da empresa, país)? O último ajuda a ingressar, o primeiro evita outro índice (ou talvez muitos, caso você também queira que seus pedidos sejam agrupados por país).

Tudo isso não é prova, mas uma indicação de que uma chave substituta para identificar exclusivamente uma linha para todos os usos, incluindo operações de junção, é preferível a uma chave comercial.

29
tzot

A chave substituta NUNCA terá um motivo para mudar. Não posso dizer o mesmo sobre as chaves naturais. Sobrenomes, e-mails, numeradores de ISBN - todos eles podem mudar um dia.

28
Rimantas

Eu odeio chaves substitutas em geral. Eles devem ser usados ​​apenas quando não houver chave natural de qualidade disponível. É bastante absurdo, quando você pensa sobre isso, pensar que adicionar dados sem sentido à sua tabela poderia melhorar as coisas.

Aqui estão as minhas razões:

  1. Ao usar chaves naturais, as tabelas são agrupadas da maneira que são pesquisadas com mais frequência, agilizando as consultas.

  2. Ao usar chaves substitutas, você deve adicionar índices exclusivos nas colunas de chaves lógicas. Você ainda precisa evitar dados duplicados lógicos. Por exemplo, você não pode permitir duas organizações com o mesmo nome em sua tabela Organização, mesmo que o pk seja uma coluna de ID substituto.

  3. Quando as chaves substitutas são usadas como chave primária, fica muito menos claro o que são as chaves primárias naturais. Ao desenvolver, você deseja saber qual conjunto de colunas torna a tabela exclusiva.

  4. Em uma a muitas cadeias de relacionamentos, as cadeias de chaves lógicas. Por exemplo, as organizações têm muitas contas e as contas têm muitas faturas. Portanto, a chave lógica da organização é OrgName. A chave lógica de contas é OrgName, AccountID. A chave lógica da fatura é OrgName, AccountID, InvoiceNumber.

    Quando chaves substitutas são usadas, as cadeias de chaves são truncadas por ter apenas uma chave estrangeira para o pai imediato. Por exemplo, a tabela Fatura não possui uma coluna OrgName. Ele possui apenas uma coluna para o AccountID. Se você deseja pesquisar faturas para uma determinada organização, precisará ingressar nas tabelas Organização, Conta e Fatura. Se você usar chaves lógicas, poderá consultar a tabela Organização diretamente.

  5. Armazenar valores-chave substitutos de tabelas de pesquisa faz com que as tabelas sejam preenchidas com números inteiros sem significado. Para visualizar os dados, devem ser criadas visualizações complexas que se juntam a todas as tabelas de pesquisa. Uma tabela de pesquisa deve conter um conjunto de valores aceitáveis ​​para uma coluna. Não deve ser codificado armazenando uma chave substituta inteira. Não há nada nas regras de normalização que sugira que você armazene um número inteiro substituto em vez do próprio valor.

  6. Eu tenho três livros diferentes de banco de dados. Nenhum deles mostra usando chaves substitutas.

26
Ken

Quero compartilhar minha experiência com você nesta guerra sem fim: D sobre o dilema natural versus substituto. Eu acho que ambas chaves substitutas (artificiais geradas automaticamente) e chaves naturais (compostas de coluna (s) com significado de domínio) têm prós e contras . Portanto, dependendo da sua situação, pode ser mais relevante escolher um método ou outro.

Como parece que muitas pessoas apresentam chaves substitutas como a solução quase perfeita e chaves naturais como praga, vou me concentrar nos argumentos do outro ponto de vista:

Desvantagens de chaves substitutas

As chaves substitutas são:

  1. Fonte dos problemas de desempenho:
    • Eles geralmente são implementados usando colunas com incremento automático, o que significa:
      • Uma viagem de ida e volta ao banco de dados toda vez que você deseja obter um novo ID (eu sei que isso pode ser aprimorado usando algoritmos de armazenamento em cache ou [seq] hilo, mas ainda assim esses métodos têm suas próprias desvantagens).
      • Se um dia você precisar mover seus dados de um esquema para outro (isso acontece com bastante frequência na minha empresa), você poderá encontrar problemas de colisão de ID. E sim, eu sei que você pode usar UUIDs, mas esses últimos requerem 32 dígitos hexadecimais! (Se você se preocupa com o tamanho do banco de dados, pode ser um problema).
      • Se você estiver usando uma sequência para todas as suas chaves substitutas, então - com certeza - você terminará com contenção no seu banco de dados.
  2. Propenso a erros. Uma sequência tem um limite de max_value, portanto, como desenvolvedor, você deve prestar atenção aos seguintes pontos:
    • Você deve alternar sua sequência (quando o valor máximo é atingido, ele volta para 1,2, ...).
    • Se você estiver usando a sequência como uma ordenação (ao longo do tempo) de seus dados, deverá lidar com o caso do ciclismo (a coluna com o ID 1 pode ser mais recente que a linha com o valor máximo de ID - 1).
    • Verifique se o seu código (e até a interface do cliente, que não deve acontecer como deveria ser um ID interno) suporta números inteiros 32b/64b que você usou para armazenar seus valores de sequência.
  3. Eles não garantem dados não duplicados. Você sempre pode ter 2 linhas com os mesmos valores de coluna, mas com um valor gerado diferente. Para mim, esse é O PROBLEMA das chaves substitutas do ponto de vista do design do banco de dados.
  4. Mais na Wikipedia ...

Mitos sobre chaves naturais

  1. Chaves compostas são menos ineficientes do que chaves substitutas. Não! Depende do mecanismo de banco de dados usado:
  2. Chaves naturais não existem na vida real. Desculpe, mas eles existem! Na indústria da aviação, por exemplo, a Tupla a seguir será sempre única em relação a um determinado voo vôo programado (companhia aérea, data de partida, data, número de vôo, número operacional, número operacional). De maneira mais geral, quando um conjunto de dados de negócios é garantido como único por um determinado padrão , esse conjunto de dados é um [bom] candidato a chave natural.
  3. As chaves naturais "poluem o esquema" das tabelas filho. Para mim, isso é mais um sentimento do que um problema real. Ter uma chave primária de 4 colunas de 2 bytes cada pode ser mais eficiente que uma única coluna de 11 bytes. Além disso, as 4 colunas podem ser usadas para consultar diretamente a tabela filho (usando as 4 colunas em uma cláusula where) sem ingressar na tabela pai.

Conclusão

Use chaves naturais quando for relevante e use chaves substitutas quando for melhor usá-las.

Espero que isso tenha ajudado alguém!

17
mwnsiri

Sempre use uma chave que não tenha significado comercial. É apenas uma boa prática.

EDIT: Eu estava tentando encontrar um link para ele online, mas não consegui. No entanto, em 'Patterns of Enterprise Archtecture' [Fowler], há uma boa explicação de por que você não deve usar outra coisa senão uma chave sem outro significado além de ser uma chave. Tudo se resume ao fato de que ele deve ter um emprego e apenas um emprego.

14
Iain Holder

Chaves substitutas são bastante úteis se você planeja usar uma ferramenta ORM para manipular/gerar suas classes de dados. Embora você possa usar chaves compostas com alguns dos mapeadores mais avançados (leia-se: hibernar), isso adiciona alguma complexidade ao seu código.

(É claro que os puristas de banco de dados argumentam que mesmo a noção de uma chave substituta é uma abominação.)

Sou fã de usar uids para chaves substitutas quando adequado. A maior vitória com eles é que você conhece a chave com antecedência, por exemplo. você pode criar uma instância de uma classe com o ID já definido e garantido que seja único, enquanto que, digamos, com uma chave inteira, você precisará usar como padrão 0 ou -1 e atualizar para um valor apropriado ao salvar/atualizar.

Os UIDs têm penalidades em termos de pesquisa e velocidade de junção, portanto, depende do aplicativo em questão se eles são desejáveis.

9
Derek Lawless

Usar uma chave substituta é melhor na minha opinião, pois não há chance de ela mudar. Quase qualquer coisa que eu possa pensar que você possa usar como chave natural pode mudar (aviso: nem sempre é verdade, mas geralmente).

Um exemplo pode ser um banco de dados de carros - à primeira vista, você pode pensar que a placa do carro possa ser usada como chave. Mas isso pode ser alterado para que seja uma má ideia. Você realmente não gostaria de descobrir isso depois liberando o aplicativo, quando alguém chega até você querendo saber por que eles não podem mudar sua chapa de matrícula para a nova e personalizada e brilhante.

6
Mark Embling

Sempre use uma única coluna, chave substituta, se possível. Isso torna as junções e as inserções/atualizações/exclusões muito mais limpas, porque você é o único responsável por rastrear uma única informação para manter o registro.

Em seguida, conforme necessário, empilhe as chaves da sua empresa como restrições ou índices exclusivos. Isso manterá a integridade dos dados intacta.

Lógica comercial/chaves naturais podem mudar, mas a chave física de uma tabela NUNCA deve mudar.

5
user7658

Em um cenário de datawarehouse, acredito que é melhor seguir o caminho-chave substituto. Duas razões:

  • Você é independente do sistema de origem e as alterações nele, como uma alteração no tipo de dados, não o afetam.
  • Seu DW precisará de menos espaço físico, pois você usará apenas tipos de dados inteiros para suas chaves substitutas. Além disso, seus índices funcionarão melhor.
4
Santiago Cepas

Este é um daqueles casos em que uma chave substituta praticamente sempre faz sentido. Há casos em que você escolhe o que é melhor para o banco de dados ou o que é melhor para o seu modelo de objeto, mas nos dois casos, usar uma chave sem sentido ou GUID é uma idéia melhor. Torna a indexação mais fácil e rápida, e é uma identidade para o seu objeto que não muda.

2
Charles Graham

Como lembrete, não é uma boa prática colocar índices agrupados em chaves substitutas aleatórias, ou seja, GUIDs que lêem XY8D7-DFD8S, pois o SQL Server não pode classificar fisicamente esses dados. Em vez disso, você deve colocar índices exclusivos nesses dados, embora também seja vantajoso executar simplesmente o SQL Profiler para as operações da tabela principal e, em seguida, colocar esses dados no Orientador de Otimização do Mecanismo de Banco de Dados.

Consulte thread @ http://social.msdn.Microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be

2
Bryan Swan

Caso 1: Sua tabela é uma tabela de pesquisa com menos de 50 tipos (inserções)

Use comercial/chaves naturais. Por exemplo:

Table: JOB with 50 inserts
CODE (primary key)       NAME               DESCRIPTION
PRG                      PROGRAMMER         A programmer is writing code
MNG                      MANAGER            A manager is doing whatever
CLN                      CLEANER            A cleaner cleans
...............
joined with
Table: PEOPLE with 100000 inserts

foreign key JOBCODE in table PEOPLE
looks at
primary key CODE in table JOB

Caso 2: Sua tabela é uma tabela com milhares de inserções

Use chaves substitutas/incremento automático. Por exemplo:

Table: ASSIGNMENT with 1000000 inserts
joined with
Table: PEOPLE with 100000 inserts

foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)

No primeiro caso:

  • Você pode selecionar todos os programadores da tabela PEOPLE sem usar a junção com a tabela JOB, mas apenas com: "SELECT * FROM PEOPLE WHERE JOBCODE = 'PRG'"

No segundo caso:

  • Suas consultas ao banco de dados são mais rápidas porque sua chave primária é um número inteiro
  • Você não precisa se preocupar em encontrar a próxima chave exclusiva, porque o próprio banco de dados fornece o próximo incremento automático.
2
Stefanos Kargas

Chaves substitutas podem ser úteis quando as informações comerciais podem mudar ou ser idênticas. Afinal, os nomes comerciais não precisam ser exclusivos em todo o país. Suponha que você lide com duas empresas chamadas Smith Electronics, uma no Kansas e outra no Michigan. Você pode distingui-los por endereço, mas isso mudará. Até o estado pode mudar; e se a Smith Electronics de Kansas City, Kansas se mover através do rio para Kansas City, Missouri? Não há maneira óbvia de manter essas empresas distintas com informações de chave natural; portanto, uma chave substituta é muito útil.

Pense na chave substituta como um número de ISBN. Geralmente, você identifica um livro por título e autor. No entanto, tenho dois livros intitulados "Pearl Harbor", de H. P. Willmott, e são definitivamente livros diferentes, não apenas edições diferentes. Em um caso como esse, eu poderia me referir à aparência dos livros, ou mais cedo ou mais tarde, mas também é bom que eu tenha o ISBN para recorrer.

2
David Thornley

Cavalo para cursos. Declarar meu viés; Sou um desenvolvedor primeiro, então estou preocupado principalmente em fornecer aos usuários um aplicativo funcional.

Eu trabalhei em sistemas com chaves naturais e tive que gastar muito tempo certificando-me de que as alterações de valor ocorressem.

Eu trabalhei em sistemas com apenas chaves substitutas, e a única desvantagem foi a falta de dados desnormalizados para particionamento.

A maioria dos desenvolvedores de PL/SQL tradicionais com quem trabalhei não gostava de chaves substitutas por causa do número de tabelas por junção, mas nossos bancos de dados de teste e produção nunca se cansaram; as junções extras não afetaram o desempenho do aplicativo. Com dialetos de banco de dados que não suportam cláusulas como "X junção interna Y em Xa = Yb" ou desenvolvedores que não usam essa sintaxe, as junções extras para chaves substitutas tornam as consultas mais difíceis de ler e mais longas para digitar e verifique: veja a publicação de @Tony Andrews. Mas se você usar um ORM ou qualquer outra estrutura de geração SQL, não perceberá. A digitação por toque também diminui.

1
WillC

Talvez não seja completamente relevante para esse tópico, mas tenho uma dor de cabeça que estou lidando com chaves substitutas. A análise pré-entregue da Oracle cria SKs geradas automaticamente em todas as suas tabelas de dimensões no armazém e também as armazena nos fatos. Portanto, sempre que elas (dimensões) precisarem ser recarregadas à medida que novas colunas são adicionadas ou precisam ser preenchidas para todos os itens na dimensão, os SKs atribuídos durante a atualização os tornam sincronizados com os valores originais armazenados no fato, forçando uma recarga completa de todas as tabelas de fatos que se juntam a ela. Eu preferiria que, mesmo que o SK fosse um número sem sentido, haveria alguma maneira de não mudar para registros originais/antigos. Como muitos sabem, a pronta entrega raramente atende às necessidades de uma organização, e temos que personalizá-lo constantemente. Agora, temos três anos de dados em nosso armazém, e as recargas completas dos sistemas Oracle Financial são muito grandes. Portanto, no meu caso, eles não são gerados a partir da entrada de dados, mas adicionados em um armazém para ajudar a relatar o desempenho. Entendi, mas a nossa muda, e é um pesadelo.

1
lrb

No caso de banco de dados point in time, é melhor ter uma combinação de chaves substitutas e chaves naturais. por exemplo. você precisa rastrear as informações de um sócio de um clube. Alguns atributos de um membro nunca mudam. por exemplo, data de nascimento, mas o nome pode mudar. Portanto, crie uma tabela Membro com uma chave substituta member_id e tenha uma coluna para DOB. Crie outra tabela chamada nome da pessoa e tenha colunas para member_id, member_fname, member_lname, date_updated. Nesta tabela, a chave natural seria member_id + date_updated.

0
kanad