Essas tabelas específicas precisam de chaves substitutas?

13

fundo

Eu tenho essas tabelas

+-------------------------+  +------------------------+
|Airport                  |  |Country                 |
|-------------------------|  |------------------------|
|airport_code string (PK) |  |country_code string (PK)|
|address string           |  |name string             |
|name  string             |  +------------------------+
+-------------------------+

+-------------------------+
|Currency                 |
|-------------------------|
|currency_code string (PK)|
|name string              |
+-------------------------+

airport_code é o código de aeroporto IATA (International Air Transport Association) , você pode vê-los em suas etiquetas de bagagem quando viaja de avião.

insira a descrição da imagem aqui

country_code é o código de país padrão ISO 3166-1 A3 , você pode vê-los nos Jogos Olímpicos.

insira a descrição da imagem aqui

currency_code é o código de moeda IS0 417 padrão de 3 caracteres , você pode vê-los em painéis de exibição de câmbios internacionais.

insira a descrição da imagem aqui

Questões

Essas PKs naturais são boas o suficiente?

O uso de padrões respeitados no mundo, aceitos por indústrias inteiras, é bom o suficiente para PKs?

Essas tabelas precisam de substitutos, não importa o quê?

Tulains Córdova
fonte

Respostas:

15

Não, eles não. Essas chaves são definitivamente boas o suficiente!

Eles são únicos, não raramente vai mudar, e significativa , que é um passo para cima sobre uma chave substituta. Essa é praticamente a definição de um bom PK.

As restrições sobre PKs serem imutáveis ​​e com número inteiro não fazem parte do Modelo Relacional (Codd) ou de qualquer padrão SQL (ANSI ou outro).

Bobson
fonte
3
As chaves primárias também devem ser imutáveis, algo que os códigos de aeroporto da IATA definitivamente não são. Eles podem ser alterados por capricho da IATA.
James Snell
3
@JamesSnell - os códigos de aeroporto IATA são tão imutáveis ​​quanto os códigos de países. Você está falando de uma mudança, talvez uma vez a cada década, se isso. Veja aqui uma discussão sobre o assunto. Existem muitos códigos desatualizados que ainda estão em vigor porque são muitos problemas para serem alterados. Além disso, é para isso que serve uma atualização do CASCADE. Chaves primárias mutáveis ​​são legítimas, se não uma ótima prática.
Bobson
2
@EricKing Esses terceiros, por acaso, são compostos por representantes de todos os principais partidos de muitos setores, os padrões são discutidos por anos e depois votados até que um consenso razoável seja alcançado. Eles também concordam com os mecanismos através dos quais qualquer alteração ou nova adição é feita. Além disso, os padrões das listas de códigos são criados, não por capricho, mas porque existe a necessidade de criar uma lista de códigos controlada, respeitada, acordada e acordada para algo, a fim de poder interoperar em todo o mundo e se comunicar adequadamente em todo o mundo.
Tulains Córdova
2
@ user61852 - Você pode dizer que esses padrões são feitos para serem chaves primárias.
Bobson
3
@ Bobson: "Há muitos códigos desatualizados que ainda estão em vigor porque são muito problemáticos para mudar" -> possivelmente porque são chaves primárias?
Maciej
2

Eu acho que necessidade é uma palavra muito forte e, em sentido estrito, as tabelas provavelmente não precisam de chaves substitutas .

No entanto, se fosse meu banco de dados, provavelmente adicionaria chaves substitutas de qualquer maneira. Talvez eu não queira necessariamente que meu design de banco de dados dependa de vários terceiros (IATA, ISO), independentemente de quão estáveis ​​sejam seus padrões. Ou talvez eu não queira depender de um padrão específico (existem outros padrões de código de moeda? Não sei). Eu provavelmente modelaria minhas tabelas com chaves substitutas da seguinte forma:

+-------------------------+  +------------------------+
|Airport                  |  |Country                 |
|-------------------------|  |------------------------|
|airport_id       int (PK)|  |country_id     int (PK) |
|iata_airport_code string |  |iso_country_code string |
|icao_airport_code string |  +------------------------+
|faa_identifier    string |  
|address           string |  
|name              string |  
+-------------------------+

+-------------------------+
|Currency                 |
|-------------------------|
|currency_id int (PK)     |
|iso_currency_code string |
|name string              |
+-------------------------+

Em outras palavras, a menos que esses códigos padrão da indústria sejam inerentemente importantes para o meu aplicativo, eu não os usaria como o PK das minhas tabelas. Eles são apenas rótulos. A maioria das minhas outras tabelas provavelmente terá chaves substitutas de qualquer maneira, e essa configuração adicionaria consistência ao meu modelo de dados. O custo de 'adicionar' as chaves substitutas é mínimo.

Atualização baseada em alguns dos comentários:

Sem conhecer o contexto das tabelas de exemplo, é impossível saber o quão importantes são os códigos de aeroporto IATA para o aplicativo usando o banco de dados. Obviamente, se os códigos IATA são de importância central e usados ​​de maneira generalizada em todo o aplicativo, pode ser a decisão correta, após análise adequada, usar os códigos como PK da tabela.

No entanto, se a tabela for apenas uma tabela de pesquisa usada em alguns cantos do aplicativo, a importância relativa dos códigos IATA pode não justificar um ponto tão proeminente na infraestrutura do banco de dados. Claro, talvez você precise fazer uma junção adicional em algumas consultas aqui e ali, mas esse esforço pode ser trivial em comparação com o esforço necessário para fazer a pesquisa para garantir que você compreenda completamente as implicações de tornar os códigos IATA os campo de chave primária. Em alguns casos, não só eu não ligo, mas não quero ter que me importar com os códigos IATA. O comentário de @James Snell abaixo é um exemplo perfeito de algo que talvez eu não queira se preocupar em afetar o PK das minhas tabelas.

Além disso, a consistência no design é importante. Se você possui um banco de dados com dezenas de tabelas que projetam consistentemente chaves substitutas e algumas tabelas de pesquisa que usam códigos de terceiros como PK, isso introduz uma inconsistência. Isso não é totalmente ruim, mas requer atenção extra na documentação e em outras que possam não ser justificadas. Eles são tabelas de pesquisa por amor de Deus, basta usar uma chave substituta para garantir a consistência.

Atualização baseada em pesquisas adicionais:

Ok, a curiosidade me mordeu e decidi fazer uma pesquisa sobre os códigos do aeroporto da IATA por diversão, começando pelos links fornecidos na pergunta.

Como se vê, os códigos IATA não são tão universais e autoritários quanto a pergunta os torna. De acordo com esta página :

A maioria dos países usa códigos ICAO de quatro caracteres , e não códigos IATA, em suas publicações aeronáuticas oficiais.

Além disso, os códigos IATA e ICAO são diferentes dos códigos de identificação FAA , que são outra maneira de identificar os aeroportos.

Meu ponto de vista é não iniciar um debate sobre quais códigos são melhores ou mais universais ou mais autoritativos ou mais abrangentes, mas mostrar exatamente por que projetar sua estrutura de banco de dados em torno de um identificador de terceiros arbitrário não é algo que eu escolheria fazer , a menos que haja um motivo comercial específico para fazer isso .

Nesse caso, acho que meu banco de dados ficaria melhor estruturado, mais estável e mais flexível, renunciando aos códigos IATA (ou qualquer código potencialmente alterável de terceiros) como candidato à chave primária e usando uma chave substituta. Ao fazer isso, posso renunciar a possíveis armadilhas que possam surgir devido à seleção da chave primária.

Eric King
fonte
1
Os padrões da IATA são bons o suficiente para as companhias aéreas, mas não para você?
Tulains Córdova
1
É claro que você terá que se juntar até a mesa do aeroporto quando quiser procurar bagagem no aeroporto de Heathrow, em Londres, porque não pode fazê-lo select * from baggage where airport_code = 'LHR', o que significa que o banco de dados é apenas utilizável na aplicação, que é muito estreita e proprietária. abordagem, especialmente quando o proprietário da empresa é quem pagou pelo banco de dados e, portanto, o possui. Além disso, você precisará escrever um código para fazer coisas comuns, como importar dados de um banco de dados para outro, para evitar colisões de PK.
Tulains Córdova
1
Os códigos IATA não são imutáveis, portanto, não podem ser considerados candidatos a PK. Exemplo: o código IDL estava em Nova York, até ser renomeado como JFK. O código IDL agora está no Mississippi.
111313 James Snell
2
@EricKing IATA e ISO se preocupam com o fato de os códigos serem suficientemente estáveis, únicos e universalmente aceitos. Isso coincide muito com o interesse de uma pessoa projetando uma mesa.
Tulains Córdova
2
@ user61852 - só porque esses são códigos padrão não significa que o sistema da companhia aérea os use como PKs (talvez você tenha mais informações aqui?). Ter uma atualização em cascata em uma escala tão grande parece uma péssima idéia.
11133 JeffO
1

Embora ter chaves substitutas nos campos seja bom, não há nada de errado em que algo a considerar possa ser o próprio tamanho da página de índice.

Como esse é um banco de dados relacional, você fará muitas junções e ter uma chave substituta de um tipo numérico pode facilitar o manuseio no banco de dados, ou seja, o tamanho da página de índice será menor e, portanto, mais rápido na pesquisa. Se este for um projeto pequeno, isso não importará e você se sairá sem problemas; no entanto, quanto maior o aplicativo, mais você reduzirá os gargalos.

Ter um BIGINT, INT, SMALLINT, TINYINT ou qualquer outro tipo de dados do tipo inteiro pode poupar alguns problemas no futuro.

Apenas meus 2 centavos

ATUALIZAR:

Projeto pequeno - usado por algumas, talvez até algumas dezenas de pessoas. Em pequena escala, projeto de demonstração, projeto para uso pessoal, algo a ser adicionado a um portfólio ao apresentar suas habilidades sem experiência e similares.

Grande projeto - usado por milhares, dezenas de milhares, milhões de usuários diariamente. Algo que você criaria para uma empresa nacional / internacional com uma enorme base de usuários.

Geralmente, o que acontece é que alguns dos registros são selecionados com frequência e o servidor armazena em cache os resultados para acesso rápido, mas de vez em quando você precisa acessar algum registro menos usado, momento em que o servidor precisaria mergulhar no índice página. (no exemplo acima, com os nomes dos aeroportos, as pessoas costumam voar em companhias aéreas domésticas, como Chichago -> Los Angeles, mas com que frequência as pessoas voam de Boston -> Zimbábue)

Se VARCHAR for usado, isso significa que o espaçamento não é uniforme, a menos que os dados sejam sempre do mesmo comprimento (nesse ponto, um valor CHAR é mais eficaz). Isso torna a pesquisa no índice mais lenta e, como o servidor já está ocupado processando milhares e milhares de consultas por segundo, agora é preciso perder tempo passando por um índice não uniforme e fazer o mesmo novamente nas junções (que é mais lento do que Para selecionar regularmente em uma tabela não otimizada, use o DW como exemplo, onde houver o mínimo de junções possível para acelerar a recuperação de dados). Além disso, se você usar UTF que também pode interferir no mecanismo de banco de dados (já vi alguns casos).

Pessoalmente, por minha própria experiência, um índice organizado adequadamente pode aumentar a velocidade de uma junção em ~ 70%, e fazer uma junção em uma coluna inteira pode acelerar a junção em cerca de ~ 25% (dependendo dos dados) . À medida que as tabelas principais começam a crescer e essas tabelas são usadas nelas, você prefere que um tipo de dados inteiro ocupe a coluna que possui alguns bytes versus um campo VARCHAR / CHAR que ocupará mais espaço. Tudo se resume a economizar espaço em disco, aumentar o desempenho e a estrutura geral de um banco de dados relacional.

Além disso, como James Snell mencionou:

As chaves primárias também devem ser imutáveis, algo que os códigos de aeroporto da IATA definitivamente não são. Eles podem ser alterados por capricho da IATA.

Portanto, levando isso em consideração, você prefere atualizar 1 registro vinculado a um número, em vez de atualizar esse registro mais todos os registros da tabela na qual você se associa.

Toni Kostelac
fonte
É um pensamento válido, mas o objetivo dessas tabelas é que haja apenas uma quantidade finita de registros em cada tabela. Se você realmente quis dizer o tamanho do código por small projecte bigger, atualize para esclarecer por que isso importa.
22413 Bobson
1
As restrições sobre PKs serem imutáveis ​​e com número inteiro não fazem parte do Modelo Relacional (Codd) ou de qualquer padrão SQL (ANSI ou outro).
Tulains Córdova
4
Os índices baseados em comprimento fixo, seqüências curtas (como códigos ISO) são tão rápidos quanto números inteiros. Índices baseados em comprimento variável, seqüências longas não são.
Tulains Córdova
Foi o que afirmei (veja a parte VARCHAR vs CHAR acima). Não tive a chance de testar uma sequência curta de comprimento fixo versus um número inteiro numérico, mas tive a chance de fazê-lo com um comprimento variável e um número inteiro
Toni Kostelac
2
Juntar desempenho é um homem de palha. Geralmente, o uso de chaves naturais significa que você não precisa de uma junção em primeiro lugar.
Mike Sherrill 'Cat Recall'
1

Se você adotar a abordagem "Eu uso chaves substitutas o tempo todo", poderá ignorar esse tipo de preocupação. Isso pode não ser uma coisa boa, porque é importante pensar um pouco nos dados, mas certamente economiza muito tempo, energia e esforço. Se alguém adotasse uma aceitação dessa regra, os exemplos listados certamente se qualificam porque é necessário um "ato do congresso" próximo para fazer a alteração.

Consultas ad hoc de um banco de dados com essas chaves naturais são certamente úteis. A criação de visualizações que fazem a mesma coisa incluindo as tabelas de pesquisa também pode funcionar. Os bancos de dados modernos fazem um trabalho muito melhor com esse tipo de coisa, a tal ponto que provavelmente não importa.

Existem alguns casos específicos nos EUA, nos quais os padrões foram alterados drasticamente: o código postal foi expandido de 5 a 9 dígitos, as abreviações do Estado para 2 letras consistentes e se livram do período (lembre-se de quando Illinois estava doente?) E a maioria das o mundo conseguiu lidar com o ano 2000. Se você tem um aplicativo em tempo real com dados espalhados por todo o mundo contendo bilhões de registros, as atualizações em cascata não são a melhor ideia, mas todos nós devemos trabalhar em locais que enfrentam esses desafios? Com esse conjunto de dados, você pode testá-lo e obter uma resposta mais difinitiva.

JeffO
fonte
+1 ótima resposta. Na maioria das vezes, as pessoas são muito dogmáticas sobre esse assunto. Muitos designers de banco de dados têm um ego gigante e se consideram os proprietários do banco de dados e dos dados. Outros entendem que o proprietário dos dados só pode usá-los através de um aplicativo específico, porque ele não consegue entender isso. Eles também preferem fazer provisões para algo que pode ou não acontecer no futuro, enquanto desfruta de um inferno de coisas que são feitas diariamente, como importar dados e escrever consultas. Também não conseguiu produzir qualquer tipo de bibliografia canônica que apóie sua visão.
Tulains Córdova
A propósito, a regra "Eu uso chaves substitutas o tempo todo" não está no Modelo Relacional (Codd) nem em nenhum padrão SQL. O esquema do dicionário de dados Oracle usa chaves naturais sempre que possível e chaves artificiais nas outras instâncias. PPDM ( ppdm.org ) também recomenda a abordagem mista e a utiliza em seu modelo. O ANSI SQL Standard não diz nada sobre todos os substitutos. Eu acho que todos os substitutos e todos os naturais são corrosivos. Alguns naturais e outros substitutos são o que o modelo relacional ensina.
Tulains Córdova