Pergunta

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

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

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

Foi útil?

Solução

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.Nada mais é do que uma restrição NOT NULL UNIQUE, e uma tabela pode ter mais de uma.

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

Outras dicas

Apenas alguns motivos 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, ou nunca, precisam ser alteradas porque não há significado vinculado ao valor.

  2. Convenção:Permite que você tenha uma convenção de nomenclatura de coluna de chave primária padronizada, em vez de ter que pensar em como unir tabelas com vários nomes para suas PKs.

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

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

A desvantagem das chaves substitutas é que elas são sem significado (citado como uma vantagem por alguns, mas...).Às vezes, isso força você a juntar muito mais tabelas em 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 que 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 ou válido ou RH mudar?" Ao qual minha resposta seria:"por que você precisar mudar isso?" Estas não são chaves "naturais" no sentido de que algum órgão externo irá legislar que doravante '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 alguma razão a maioria das pessoas aqui parece defender.

Veja também: minha resposta para outra pergunta

Chaves substitutas (normalmente números inteiros) têm o valor agregado de tornar suas relações de tabela mais rápidas e mais econômicas em armazenamento e velocidade de atualização (melhor ainda, chaves estrangeiras não precisam ser atualizadas ao usar chaves substitutas, em contraste com campos-chave de negócios, isso muda 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.Pense em uma tabela de Pessoas:os nomes podem mudar e não são garantidos como exclusivos.

Pense em empresas:você é uma empresa Merkin feliz fazendo negócios com outras empresas em Merkia.Você é inteligente o suficiente para não usar o nome da empresa como chave primária, então usa o ID exclusivo da empresa do governo Merkia em sua totalidade de 10 caracteres alfanuméricos.Então Merkia muda os IDs da empresa porque 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 mudança que não deveria envolver você em primeiro lugar.Mais tarde, seu negócio se expande e agora você trabalha com uma empresa em Freedonia.O ID da empresa Freedonian tem até 16 caracteres.Você precisa ampliar a chave primária do ID da empresa (também os campos de chave estrangeira em Pedidos, Emissões, Transferências de Dinheiro etc.), adicionando um campo País na chave primária (também nas chaves estrangeiras).Ai!Guerra civil na Freedonia, 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.Aliás, qual é a sua chave primária?(País, CompanyID) ou (CompanyID, País)?O último ajuda nas junções, o primeiro evita outro índice (ou talvez muitos, caso você queira que seus pedidos também sejam agrupados por país).

Tudo isso não é uma 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.

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

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

Aqui estão meus motivos:

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

  2. Ao usar chaves substitutas, você deve adicionar índices exclusivos em 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 pk seja uma coluna de id substituta.

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

  4. Em uma ou muitas cadeias de relacionamento, 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 tendo apenas uma chave estrangeira para o pai imediato.Por exemplo, a tabela Fatura não possui uma coluna OrgName.Possui apenas uma coluna para o AccountID.Se quiser pesquisar faturas de uma determinada organização, você 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 sentido.Para visualizar os dados, devem ser criadas visualizações complexas que se juntem a todas as tabelas de pesquisa.Uma tabela de pesquisa destina-se a 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 valor em si.

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

Quero compartilhar minha experiência com você nesta guerra sem fim: D sobre o dilema da chave natural versus substituta.eu penso isso ambos chaves substitutas (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 as chaves substitutas como a solução quase perfeita e as chaves naturais como a praga, vou me concentrar nos argumentos do outro ponto de vista:

Desvantagens das chaves substitutas

As chaves substitutas são:

  1. Fonte de problemas de desempenho:
    • Eles geralmente são implementados usando colunas incrementadas automaticamente, o que significa:
      • Uma viagem de ida e volta ao banco de dados cada vez que você deseja obter um novo ID (eu sei que isso pode ser melhorado usando cache ou algoritmos semelhantes ao [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 regularidade, pelo menos na minha empresa), 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, isso pode ser um problema).
      • Se você estiver usando uma sequência para todas as suas chaves substitutas, então - com certeza - você acabará com contenção em seu banco de dados.
  2. Propenso a erros.Uma sequência tem um limite max_value então - 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 de ciclismo (a coluna com ID 1 pode ser mais recente que a linha com valor máximo de ID - 1).
    • Certifique-se de que seu código (e até mesmo suas interfaces de cliente, o que não deveria acontecer, pois 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 isso é O problema de chaves substitutas do ponto de vista do design do banco de dados.
  4. Mais na Wikipédia...

Mitos sobre chaves naturais

  1. As chaves compostas são menos ineficientes que as chaves substitutas.Não!Depende do mecanismo de banco de dados usado:
  2. As 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 agendado voo (companhia aérea, data de partida, número do voo, sufixo operacional).De modo mais geral, quando é garantido que um conjunto de dados de negócios seja exclusivo por um determinado padrão então este conjunto de dados é um [bom] candidato de chave natural.
  3. As chaves naturais "poluem o esquema" das tabelas filhas.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 do que uma única coluna de 11 bytes.Além disso, as 4 colunas podem ser usadas para consultar a tabela filha diretamente (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!

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

EDITAR:Tentei encontrar um link para ele online, mas não consegui.Contudo em 'Padrões de arquitetura empresarial' [Fowler] tem uma boa explicação de por que você não deve usar nada além de uma chave sem nenhum significado além de ser uma chave.Tudo se resume ao fato de que deveria ter um emprego e apenas um emprego.

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:hibernate), adiciona alguma complexidade ao seu código.

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

Sou fã de usar uids para chaves substitutas quando adequado.A principal vantagem deles é 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 como exclusivo, enquanto com, digamos, uma chave inteira, você precisará definir o padrão como 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.

Usar uma chave substituta é melhor na minha opinião, pois não há chance de ela mudar.Quase tudo que consigo pensar que você possa usar como chave natural pode mudar (isenção de responsabilidade:nem sempre é verdade, mas comumente).

Um exemplo pode ser um banco de dados de carros - à primeira vista, você pode pensar que a placa do carro poderia ser usada como chave.Mas isso poderia ser alterado, então seria uma má ideia.Você realmente não gostaria de descobrir isso depois lançando o aplicativo, quando alguém vem até você querendo saber por que não pode mudar sua placa para uma nova e personalizada.

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

Em seguida, conforme necessário, empilhe suas chaves comerciais como restrições ou índices exclusivos.Isso manterá a integridade dos seus dados intacta.

A lógica de negócios/chaves naturais podem mudar, mas a chave física de uma tabela NUNCA deve mudar.

Em um cenário de datawarehouse, acredito que seja melhor seguir o caminho da chave substituta.Duas razões:

  • Você é independente do sistema de origem e as alterações nele - como uma alteração no tipo de dados - não afetarão você.
  • 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.

As 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 em Michigan.Você pode distingui-los por endereço, mas isso vai mudar.Até o estado pode mudar;e se a Smith Electronics de Kansas City, Kansas, atravessar o rio para Kansas City, Missouri?Não há uma maneira óbvia de manter esses negócios distintos com informações de chave natural; portanto, uma chave substituta é muito útil.

Pense na chave substituta como um número ISBN.Normalmente, você identifica um livro pelo 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.Num caso como esse, eu poderia me referir à aparência dos livros, ou o anterior versus o posterior, mas é bom ter o ISBN para recorrer.

Como lembrete, não é uma boa prática colocar índices agrupados em chaves substitutas aleatórias, ou seja,GUIDs que leem XY8D7-DFD8S, pois o SQL Server não tem capacidade de classificar fisicamente esses dados.Em vez disso, você deve colocar índices exclusivos nesses dados, embora também possa ser benéfico simplesmente executar 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.

Veja o tópico @ http://social.msdn.microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be

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

Usar chaves empresariais/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 mesa é uma mesa com milhares de inserções

Usar chaves substitutas/de 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 na tabela PEOPLE sem usar join com a tabela JOB, mas apenas com:"SELECIONE * DE PESSOAS ONDE 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.

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 em ambos os casos, usar uma chave ou GUID sem sentido é uma ideia melhor.Torna a indexação mais fácil e rápida e é uma identidade para o seu objeto que não muda.

Cavalo para cursos.Para declarar meu preconceito;Primeiro sou um desenvolvedor, então estou preocupado principalmente em fornecer aos usuários um aplicativo funcional.

Trabalhei em sistemas com chaves naturais e tive que gastar muito tempo garantindo que as mudanças de valor ocorressem.

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

A maioria dos desenvolvedores 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 foram muito complicados;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 inner join Y on X.a = Y.b", 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 demoradas para digitar e verificar:veja a postagem de @Tony Andrews.Mas se você usar um ORM ou qualquer outra estrutura de geração de SQL, você não notará isso.A digitação também atenua.

Talvez não seja totalmente relevante para este tópico, mas estou com dor de cabeça ao lidar com chaves substitutas.A análise pré-entregue da Oracle cria SKs gerados automaticamente em todas as suas tabelas de dimensão no warehouse e também os armazena nos fatos.Portanto, sempre que elas (dimensões) precisarem ser recarregadas à medida que novas colunas forem adicionadas ou precisarem ser preenchidas para todos os itens da dimensão, os SKs atribuídos durante a atualização fazem com que os SKs fiquem fora de sincronia 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, houvesse alguma maneira de ele não poder ser alterado para registros originais/antigos.Como muitos sabem, o out-of-the-box raramente atende às necessidades de uma organização e temos que personalizá-lo constantemente.Agora temos três anos de dados em nosso warehouse 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 warehouse para ajudar a relatar o desempenho.Eu entendo, mas os nossos mudam e é um pesadelo.

No caso de banco de dados pontual, é melhor ter uma combinação de chaves substitutas e naturais.por exemplo.você precisa rastrear as informações de um membro de um clube.Alguns atributos de um membro nunca mudam.por exemplo, data de nascimento, mas o nome pode mudar.Portanto, crie uma tabela Member 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top