Por que as correspondências de chave primária / chave estrangeira não são usadas para junções?


48

Tanto quanto pude descobrir, muitos DBMSs (por exemplo, mysql, postgres, mssql) usam combinações fk e pk apenas para restringir alterações nos dados, mas raramente são usados ​​de forma nativa para selecionar automaticamente colunas para ingressar (como a junção natural faz com nomes). Por que é que? Se você já definiu um relacionamento entre duas tabelas com um pk / fk, por que o banco de dados não pode descobrir que, se eu ingressar nessas tabelas, quero juntá-las nas colunas pk / fk?

EDIT: para esclarecer isso um pouco:

suponha que eu tenho uma tabela1 e uma tabela2. A tabela 1 tem uma chave estrangeira na coluna a, que faz referência à chave primária na tabela 2, a coluna b. Agora, se eu ingressar nessas tabelas, terei que fazer algo assim:

SELECT * FROM table1
JOIN table2 ON table1.a = table2.b

No entanto, eu já defini usando minhas chaves que table1.a faz referência a table2.b, portanto, parece-me que não deve ser difícil criar um sistema DBMS usando automaticamente table1.a e table2.b como as colunas de junção, de modo que alguém possa simplesmente usar:

SELECT * FROM table1
AUTO JOIN table2

No entanto, muitos DBMS não parecem implementar algo assim.

Respostas:


32

Em muitos casos, há mais de uma maneira de juntar duas tabelas; Veja as outras respostas para muitos exemplos. Obviamente, pode-se dizer que seria um erro usar a 'junção automática' nesses casos. Então, apenas alguns casos simples em que ele pode ser usado seria deixado.

No entanto, há uma grande desvantagem! As consultas corretas hoje podem se tornar um erro amanhã, adicionando um segundo FK à mesma tabela!

Deixe-me dizer isso novamente: adicionando colunas, as consultas que não usam essas colunas podem passar de 'correto' para 'erro'!

Esse é um pesadelo de manutenção, que qualquer guia de estilo sensato proibiria usar esse recurso. A maioria já proíbe select *pela mesma razão!

Tudo isso seria aceitável, se o desempenho fosse aprimorado. No entanto, esse não é o caso.

Resumindo, esse recurso pode ser usado apenas em um conjunto limitado de casos simples, não aumenta o desempenho e a maioria dos guias de estilo proibiria seu uso de qualquer maneira.

Portanto, não é surpreendente que a maioria dos fornecedores de banco de dados opte por gastar seu tempo em coisas mais importantes.


1
É provável que haja um pequeno impacto no desempenho, pois ele precisa descobrir as colunas de junção em vez de aumentá-las.
HLGEM

1
@HLGEM, isso pode ser armazenado em cache e também é irrelevante para consultas maiores. A vantagem é que podemos ter certeza de que as chaves não serão perdidas devido a algum erro humano.
Pacerier 10/10

A adição e alteração de colunas também pode ser interrompida NATURAL JOIN(é por isso que geralmente as evito), mas não acho que isso deva significar que um dbms não possa implementar uma maneira automática de associar tabelas com base em chaves estrangeiras.
Jay K

2
Vários casos? Em um banco de dados de mil tabelas, só tenho alguns casos de mais de uma relação entre duas tabelas. De qualquer forma, isso não é um problema, seria suficiente adicionar o nome da relação AUTO JOIN mytable THROUGH myrelation, seria muito bom.
Teejay

Isso é o que fazemos no nosso construtor de .NET SQL custom-built, com intellisense, comoInnerJoin(SRC_TABLE.rDEST_TABLE.REL_NAME_F01)
Teejay

27

Uma chave estrangeira deve restringir os dados. ou seja, impor integridade referencial. É isso aí. Nada mais.

  1. Você pode ter várias chaves estrangeiras na mesma tabela. Considere o seguinte em que uma remessa tem um ponto inicial e um ponto final.

    table: USA_States
    StateID
    StateName
    
    table: Shipment
    ShipmentID
    PickupStateID Foreign key
    DeliveryStateID Foreign key

    Você pode querer participar com base no estado de recebimento. Talvez você queira ingressar no estado de entrega. Talvez você queira realizar 2 junções para ambos! O mecanismo sql não tem como saber o que você deseja.

  2. Você geralmente cruza valores escalares de junção. Embora os escalares geralmente sejam o resultado de cálculos intermediários, às vezes você terá uma tabela de finalidade especial com exatamente 1 registro. Se o mecanismo tentasse detectar uma chave estrangeira para a junção ... não faria sentido porque as junções cruzadas nunca correspondem a uma coluna.

  3. Em alguns casos especiais, você ingressará em colunas nas quais nenhuma é única. Portanto, a presença de um PK / FK nessas colunas é impossível.

  4. Você pode pensar que os pontos 2 e 3 acima não são relevantes, pois suas perguntas é sobre quando há É a / relacionamento único PK FK entre tabelas. No entanto, a presença de PK / FK único entre as tabelas não significa que você não pode ter outros campos para ingressar além do PK / FK. O mecanismo sql não saberia em quais campos você deseja ingressar.

  5. Digamos que você tenha uma tabela "USA_States" e mais 5 tabelas com um FK para os estados. As "cinco" tabelas também têm algumas chaves estrangeiras entre si. O mecanismo sql deve ingressar automaticamente nas "cinco" tabelas com "USA_States"? Ou deveria juntar os "cinco" um ao outro? Ambos? Você pode configurar os relacionamentos para que o mecanismo sql entre em um loop infinito tentando juntar as coisas. Nessa situação, é impossível que o mecanismo sql adivinhe o que você deseja.

Em resumo: PK / FK não tem nada a ver com junções de tabelas. São coisas separadas e não relacionadas. É apenas um acidente da natureza que você costuma participar das colunas PK / FK.

Deseja que o mecanismo sql adivinhe se é uma junção completa, esquerda, direita ou interna? Acho que não. Embora isso possa ser um pecado menor do que adivinhar as colunas para se juntar.


7
Considero chaves estrangeiras e normalização muito relevantes para junções de tabelas.

3
Seus argumentos são mantidos quando a palavra-chave JOIN normal sempre tenta corresponder a isso (como fiz errado no meu exemplo, vou corrigir isso). No entanto, muitas junções podem ser derivadas diretamente apenas das junções, portanto não vejo nenhuma razão para que não possa haver nenhuma sintaxe explícita para ingressar nelas. Muitos DBMSs têm uma junção natural, que basicamente faz a mesma coisa, mas com nomes de colunas (= incorretos). O mesmo poderia ser feito com esse tipo de junção, por exemplo, especificando uma operação AUTO JOIN.

5
"É apenas um acidente da natureza que você costuma participar das colunas PK / FK" - não estou convencido!
onedaywhen

2
"Normalização?" Penso que o pensamento aqui é que, se você começou com um relvar de 1NF e depois se decompôs em relvares de 6NF, as chances são de que: a) eles teriam chaves estrangeiras na implementação eb) seriam frequentemente associados a consultas.
onedaywhen

4
Gostaria de votar se não existisse "PK / FK não tem nada a ver com junções de tabelas".
ypercubeᵀᴹ

11

o conceito de "associação". Relações r1e r2são associáveis ​​se e somente se atributos com o mesmo nome forem do mesmo tipo ... esse conceito se aplica não apenas à associação como tal, mas também a várias outras operações [como união].

SQL e teoria relacional: como escrever código SQL preciso por data de CJ

O SQL padrão já possui esse recurso, conhecido como NATURAL JOIN, e foi implementado no mySQL.

Embora sua sugestão não seja tão digna, parece razoável. Com o SQL Server (que não possui suporteNATURAL JOIN ), uso o SQL Prompt no Management Studio: ao escrever um INNER JOINInteliSense, sugiro ONcláusulas com base em nomes de atributos comuns e chaves estrangeiras, e acho muito útil. No entanto, não desejo muito ver um novo tipo de associação SQL (padrão) para isso.


1
A junção natural e a junção em colunas comuns são distintas de e ortogonais à noção de junção no FK-PK. (Veja a minha resposta.)
philipxy

@ philipxy: concordou, eu não pretendia sugerir o contrário. (O seu é uma excelente resposta!) #
04718

9

SQL veio primeiro!

As restrições de Chaves estrangeiras e Chaves estrangeiras vieram mais tarde e são essencialmente uma otimização para aplicativos no estilo "transação".

Os bancos de dados relacionais foram originalmente concebidos como um método de aplicação de consultas complexas em conjuntos de dados de uma maneira que fosse matematicamente comprovável usando álgebra relacional. IE para um determinado conjunto de dados e uma determinada consulta, há sempre uma única resposta correta.

Os bancos de dados relacionais percorreram um longo caminho desde então, e o uso primário como camada de persistência para sistemas transacionais não foi o que CODD et. tudo previsto.

No entanto, o corpo de padrões ANSI para todos os seus objetivos conflitantes e políticas de fornecedores sempre se esforçou para preservar propriedades "prováveis ​​matematicamente" do SQL.

Se você permitisse que o banco de dados inferisse as propriedades de junção dos dados de chave estrangeira "ocultos", você perderia essa propriedade (considere a ambiguidade se houvesse mais de um conjunto de chaves estrangeiras definido).

Além disso, um programador que lê o SQL não saberia necessariamente quais chaves estrangeiras foram definidas atualmente para as duas tabelas e precisaria examinar o esquema do banco de dados para descobrir o que a consulta estava fazendo.


3
Obrigado, isso fez sentido para mim! No entanto, as junções naturais não têm os mesmos problemas? Embora as junções naturais ainda tenham problemas maiores, muitos DBMS as suportam. A IMO uma junção baseada em pk / fk seria uma junção natural feita corretamente.

1
Não há diferença quanto à maioria dos mecanismos de banco de dados entre uma junção natural e um "JOIN ... ON" explícito. O mecanismo analisa a consulta e faz a junção da melhor maneira possível, com base nos vários predicados. O uso de uma junção explícita não força o uso de um índice ou caminho de acesso específico, existe principalmente para suportar a sintaxe de junção "ESQUERDA, EXTERNA, INTERIOR", que precisa conhecer os predicados de junção explícita para saber quando inserir uma linha "ausente" .

6
SQL não veio primeiro! O modelo relacional (que incluía o conceito de chaves estrangeiras, é claro) foi esboçado pela primeira vez pela EFCodd em 1969. SEQUEL, como era na época, não via a luz do dia até 1974. Seus inventores deixaram claro desde o início que O SEQUEL / SQL foi criado com base no modelo relacional pré-existente - embora o SQL não tenha sido uma linguagem verdadeiramente relacional.
Nvogel

@sqlvogel - true! Deveria ter formulado "SQL foi implementado primeiro".
James Anderson

CJ Date em 'Introdução aos sistemas de banco de dados' (p276) diz que Codd inventou o conceito de chave estrangeira; não diz quando, mas presumo que foi antes da primeira implementação do SQL.
precisa saber é o seguinte

7

Embora você tenha definido um relacionamento de Chave estrangeira, isso não significa que é assim que você deseja unir as tabelas em todas as consultas. É o método mais provável para ingressar nas tabelas, mas há casos em que não está correto.

  • Você pode usar um produto cartesiano das duas tabelas ou parte dela para algum propósito.
  • Pode haver outros campos nos quais você pode ingressar para outra finalidade.
  • Se você estiver ingressando em três ou mais tabelas, uma delas poderá estar relacionada a duas ou mais tabelas. Nesse caso, geralmente apenas um dos possíveis relacionamentos FK pode ser apropriado na consulta.

7

Você pode estar operando com uma suposição falsa. Você diz 'até onde pode descobrir', mas não fornece nenhuma prova empírica ou probatória. Se o pk ou o fk forem o melhor índice para uma consulta, ele será usado. Não sei por que você está vendo isso, mas meu palpite é consultas mal formadas.


Edite agora que a pergunta foi totalmente reescrita: o caso que você está descrevendo seria apenas para um conjunto muito pequeno de consultas. E se houver 12 tabelas Registradas? E se não houver FKs .... Mesmo se houvesse uma associação padrão, eu ainda especificaria sempre a associação apenas para facilitar a leitura. (Eu não quero ter que olhar para os dados e tentar descobrir em que está sendo juntado)

Algumas ferramentas de consulta, na verdade, fazem uma associação automática para você e permitem remover ou editar a associação. Acho Query Builder do MS Access faz isso.

Por fim, o padrão ANSII afirma que a associação deve ser especificada. Essa é a razão suficiente para não permitir.


3
Desculpe, talvez eu não tenha sido claro o suficiente. Não estou falando de índices, estou falando de junções. Suponha que eu tenha table1 e table2, com um fk na table1.a que aponte para table2.b. Se eu ingressar nessas tabelas, terei que dizer explicitamente que desejo ingressá- las nas colunas aeb (por exemplo, 'SELECT * FROM table1 JOIN table2 ON table1.a = table2.b '), enquanto já definido no meu banco de dados esquema que esses dois estão relacionados. A questão é por que não consigo fazer 'SELECT * FROM table1 JOIN table2' e deixar o DBMS escolher automaticamente as colunas de junção com base no fk / pk.

3
Especialmente a legibilidade fazia sentido para mim! No entanto, que o padrão diz isso não é realmente um bom argumento IMO. Muitos padrões fizeram escolhas erradas antes (HTML, por exemplo).

3

Há muitas razões pelas quais o banco de dados não pode fazer isso com segurança, incluindo o fato de que adicionar / remover chaves estrangeiras alterará o significado de consultas pré-escritas, incluindo consultas no código-fonte do aplicativo. A maioria dos bancos de dados também não possui um bom conjunto de chaves estrangeiras que cobrem todas as junções possíveis que você provavelmente deseja. Também para melhor ou para o melhor, as Chaves Estrangeiras são frequentemente removidas para acelerar os sistemas e não podem ser usadas em tabelas carregadas na ordem "errada" do arquivo.

No entanto, não há razão para que uma ferramenta de design de consulta ou o editor de texto não consiga concluir automaticamente uma junção com a ajuda de Chaves estrangeiras da mesma maneira que elas fornecem inteligência no nome da coluna. Você pode editar a consulta se a ferramenta estiver errada e salvar uma consulta completamente definida. Essa ferramenta também pode ser útil para usar a convenção de nomear colunas de Chaves estrangeiras pelo nome da tabela "pai" e colunas com o mesmo nome na tabela pai / filho, etc.

(Minha esposa ainda não consegue entender a diferença entre o Management Studio e o Sql Server e fala sobre como iniciar o sql server quando inicia o management studio!)


3

A junção natural "automaticamente" se une à igualdade de colunas comuns, mas você deve escrever apenas se é isso que deseja com base nos significados da tabela e no resultado desejado. Não há "automaticamente" saber como duas tabelas "devem" ser unidas ou de qualquer outra forma qualquer tabela "deve" aparecer em uma consulta. Não precisamos conhecer restrições a serem consultadas. Sua presença significa apenas que as entradas podem ser limitadas e, consequentemente, a saída também. Você pode definir algum tipo de operador join_on_fk_to_pk que "junte-se" automaticamente por restrições declaradas; mas se você quiser que o significado da consulta permaneça o mesmo, se apenas as restrições mudarem, mas não os significados da tabela, será necessário alterar essa consulta para não usar as novas restrições declaradas.já deixa o significado da mesma forma, apesar de qualquer alteração de restrição .

As restrições mantidas (incluindo PKs, FKs, UNIQUE & CHECK) não afetam o significado das tabelas. Obviamente, se os significados da tabela mudarem, as restrições poderão mudar. Mas se as restrições mudarem, isso não significa que as consultas devem mudar.

Não é necessário conhecer restrições a serem consultadas. Conhecer restrições significa que podemos usar outras expressões que, sem a restrição de retenção, não retornariam a mesma resposta. Por exemplo, esperando via UNIQUE que uma tabela tenha uma linha, para que possamos usá-la como escalar. Essas consultas podem ser interrompidas se a restrição foi assumida, mas não declarada. Mas declarar uma restrição que a consulta não assumiu não pode quebrá-la.

Existe alguma regra prática para construir a consulta SQL a partir de uma descrição legível por humanos?


2

O motivo é que existe o IDIOMA e os principais subjacentes. O idioma é escasso e carece de muitos recursos que você esperaria ver em um idioma de uso geral. Isso simplesmente é um recurso interessante que não foi adicionado ao idioma e provavelmente não será. Não é uma língua morta, então há alguma esperança, mas eu não ficaria otimista.

Como outros já apontaram, algumas implementações usam uma extensão em que join (coluna) une duas tabelas com base em um nome de coluna comum, que é um pouco semelhante. Mas não é amplamente divulgado. Observe que essa extensão é diferente da SELECT * FROM employee NATURAL JOIN department;sintaxe, que não inclui uma maneira de especificar quais colunas usar. Também não confie em um relacionamento entre as tabelas, o que as torna não confiáveis ​​(a sintaxe de junção natural é maior que a extensão).

Não há obstáculo fundamental para "tabela de junção interna no PKFK", em que PKFK é uma palavra-chave que significa "o relacionamento de chave estrangeira definido entre as duas tabelas"; pode haver problemas com vários fk na mesma tabela, mas isso pode simplesmente causar um erro. A questão é: as pessoas que projetam o idioma consideram que: a) uma boa idéia eb) melhor trabalhar do que alguma outra mudança de idioma ...


3
Isso pressupõe que é uma boa ideia que eles já devessem ter feito. Também é provável que eles já tenham considerado isso e tenham decidido não fazê-lo. Talvez seja uma péssima idéia na prática: Sjoerd mencionou um exemplo, onde uma consulta pode ser interrompida apenas pela adição de uma nova coluna e um relacionamento FK. Lord Tydus também explica que chaves estrangeiras têm uma responsabilidade diferente de ditar a maneira como suas tabelas devem ser unidas.

1
@JonathanHobbs: Eu quis dizer que minha resposta é geralmente neutra. Mas abandonar a neutralidade. Isso de fato o isolaria disso até certo ponto, desde que o relacionamento da tabela fosse mantido, as alterações da coluna poderiam ser feitas com segurança. Isso provavelmente aumentaria o uso dos relacionamentos do FK, pois seria útil para algo que não seja o RI. estão no PK ou incluem o Pk.Para manipular o multi-fk, use o nome da coluna.
jmoreno

1

Se a omissão da cláusula ON seguir os campos com base na integridade referencial, como você faria um produto cartesiano?

Editar: usando AUTO As vantagens disso são um pouco menos de digitação e você não precisa saber como elas são unidas ou se lembrar de uma união complicada. Se o relacionamento mudar, ele será tratado automaticamente, mas isso raramente acontece, exceto no desenvolvimento inicial.

O que você precisa fazer agora é decidir se todas as suas junções AUTO serão mantidas durante uma alteração no relacionamento para corresponder à intenção da sua declaração de seleção.


@ JeffO: a principal vantagem é que ele expressa a intenção com mais precisão, de maneira declarativa muito clara. As junções nos nomes de colunas não informam nada, exceto o fato de que parte do conteúdo das colunas é semelhante ao de outra (mas pode não ser do mesmo tipo). A juntar-se em um ref fk, diz-lhe que não é um ref fk, nenhuma lista de colunas significaria havia apenas 1 fk entre as tabelas, ou, inversamente, que há 1+ (considere uma chave de várias colunas com mais de 1 ref o que acontece quando você mistura as colunas c1 = fk1_c1 e c2 = fk2_c2). Mesmo com mais digitação em média, isso seria bom.
jmoreno

Usar (INNER) JOIN sem ON não é o SQL padrão. Vírgula, CROSS JOIN e (INTERNO ou EXTERIOR) JOIN ON 0 = 0 retornam produto cartesiano.
philipxy

-1

por que o banco de dados não pode descobrir que, se eu ingressar nessas tabelas, quero juntá-las nas colunas pk / fk?

Partes do motivo são:

1 - em teoria, você pode juntar tabelas em colunas arbitrárias a partir das duas tabelas. Embora isso não seja uma prática comum, é válido. Lembre-se de que o SQL é como uma linguagem de programação, ele não entende quais informações estão nas colunas de curso e nomes; para o SQL, não significa muito a esse respeito.

2 - Existem diferentes tipos de junções (esquerda, direita, interna) - as junções internas são apenas 1 delas.

3 - O padrão SQL pode ser guiado pelo princípio de ser uma linguagem de nível inferior que permite aos dialetos de nível superior formar inteligência usando-a. A comparação é um pouco mais clara se você pensar em um idioma de quarta geração vs. um idioma de terceira geração. De fato, uma ferramenta que usei, o IEF, permitiu que você escrevesse algo assim:

ReadEach Customer 
Where Customer Places Orders and That Customer LivesIn "California" 
and OrderValue > 100.00

Em resumo, sua sugestão é interessante e pode ser implementada como parte do padrão ou como um procedimento armazenado (o padrão seria uma Junção Interna).


-10

Bom, eu acredito que você está completamente certo, o SQL nesse tópico é bastante idiota , e eu lembro de ter pensado o mesmo que você pensava sobre chaves estrangeiras enquanto aprendia SQL há dez anos.

Ok, dado que, finalmente tive que passar no exame; e para passar, eu tive que deixar ir . O SQL é mais um naufrágio do que qualquer um pode admitir, seu caminho de padronização é um desastre completo e algumas implementações são ameaçadoras . Ainda assim, é bastante útil, em geral. (Eu não sou um Lududita K / V)

Chaves estrangeiras, então ... não são tão úteis assim. Eles são um conceito importante no modelo relacional , ok, mas o recurso SQL com o mesmo nome não se compara bem.

Diga-lo direto: não use esse recurso SQL chamado Foreign Keyem tudo , até atingir algum grande sistema com problemas de desempenho. Informar explicitamente ao mecanismo qual campo é uma chave estrangeira e qual não é é usado apenas para indexação e é invisível para o usuário do banco de dados.

Isso é enganador?
Sim.

Eles vão torná-lo mais poderoso agora, depois de 30 anos de pessoas sendo enganadas?
Sem chance.

Ignorando completamente chaves estrangeiras até necessário ... corrigiu o SQL para mim?
Sim!

E por que diabos tudo isso aconteceu em primeiro lugar?
Bem, o recurso que chamamos de chaves estrangeiras foi adicionado posteriormente ao SQL; SQL é um padrão que evoluiu ao longo do tempo, de baixo para cima. Os fornecedores implementaram recursos ridículos, enquanto os organismos padrão se enfrentaram.

Chaves estrangeiras, como dito, onde apenas destinavam-se à indexação e não havia construção JOIN disponível. (junta-se onde as consultas são feitas SELECT, as JOINconsultas são bastante recentes e destinam-se apenas à SELECTfuncionalidade de alias ). Eles provavelmente consideraram que chamar esse sinalizador de indexação FOREIGN KEYfoi um truque de nomeação inteligente sobre os conceitos da teoria do banco de dados relacional.


13
No que diz respeito às chaves estrangeiras, suponho que você só tocou no mecanismo MyISAM no MySQL? Porque mesmo desconsiderando esse pequeno discurso, tudo nessa resposta está errado.

Os Fk's não são usados ​​para indexação; na verdade, um problema comum é não ter um índice na coluna fk, o que pode ter um impacto dramático no desempenho.
jmoreno 16/02
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.