Estou tentando entender como as chaves estrangeiras funcionariam de uma perspectiva de processamento interno (estou usando o SQLServer). Em outras palavras, como uma tabela seria afetada pela adição de uma chave estrangeira?
Digamos que eu tenha duas tabelas (PK são não nulos):
TableA : PK Student_ID, StudentName, StudentAddress
TableB : PK Books_ID, FK Student_ID, Books_IssueMonth
select Student_ID from TableB where Books_IssueMonth=January;
Quando eu executo uma instrução sql ao TableB
chamar Student_ID
, o sistema é informado para primeiro procurá-lo TableA
e, em seguida, apontar para o índice clusterizado ( Books_ID
) em TableB
?
Seriam buscas de duas mesas?
ou seria uma busca na TableA e scan na TableB?
Uma restrição de chave estrangeira na TableB tem efeito em três níveis (pelo menos).
Quando você
INSERT INTO TableB
encontra uma linha em que Student_ID não é nulo, o valor de Student_ID é procurado na TabelaA. Se não estiver lá, a inserção falhará (a linha não será inserida no banco de dados); se a inserção fizer parte de uma transação maior, a própria transação falhará.UPDATE
s daTableB
coluna envolventeStudent_ID
se comportam de maneira semelhante (o novo valor para Student_ID é procurado na TabelaA).Quando você
UPDATE TableA SET Student_ID=<value>
ouDELETE FROM TableA
qualquer linha, o valor antigo da colunaStudent_ID
será pesquisado na TabelaB. Isso incorre em alguma penalidade de desempenho (especialmente se a coluna não estiver indexada na TableB, mas o que normalmente é chamado deforeign key covering index
). Se o valor for encontrado então: se a restrição FK não especificou o que fazer em UPDATE ou DELETE, o UPDATE ou INSERT falhará, porque violaria a restrição. Se o FK especificar o que fazer em UPDATE e/ou DELETE, a ação especificada será executada. Se a condição forCASCADE
esta, poderá disparar UPDATES/DELETEs em tabelas referenciadas pela tabela referenciada, recursivamente.Em a
SELECT
, uma restrição FK não terá nenhuma penalidade . Pode ter alguns efeitos benéficos para o planejador do banco de dados. A condiçãoTableB.Student_ID IS NULL OR TableB.Student_ID in (SELECT Student_ID FROM TableA)
é um fato conhecido pelo planejador, e isso pode ser usado com alguma vantagem (por exemplo, se tal condição existir em uma cláusula WHERE, ela pode ser substituída por uma constante TRUE, facilitando o processamento). Outra otimização seria converter aTableB LEFT JOIN TableA USING (Student_ID)
em um INNER JOIN, se Student_ID for conhecido como não nulo, porque o planejador sabe que todas as linhas serão encontradas na TabelaA. Quanto lucro os diferentes planejadores obterão desse conhecimento dependerá fortemente da implementação.Selecionar linhas de
TableB
(seTableA
também não for especificado na cláusula FROM) não terá nenhum efeito na buscaStudent_ID
emTableA
. As restrições de chave estrangeira são aplicadas quando os dados são inseridos ou atualizados e, em seguida, conhecidos como retidos quando os dados são selecionados.NOTA : Uma restrição FK pode especificar o que fazer quando o Student_ID pai for UPDATED ou DELETED. A sintaxe específica pode ter pequenas variações, mas é tipicamente
ON {UPDATE|DELETE} {RESTRICT|NO ACTION|SET DEFAULT|SET NULL|CASCADE}
. Verifique como isso funciona para PostgreSQL , MySQL , Oracle e SQL Server .para a instrução SELECT específica sobre a qual você perguntou, não há motivo para a consulta ir para a Tabela A, pois a consulta menciona apenas a Tabela B. Pelo menos isso é verdade para qualquer produto de banco de dados com o qual trabalhei. Você não disse com qual produto de banco de dados você trabalha.
A questão sobre qual estratégia ele usaria para encontrar todas as linhas onde Books_IssueMonth = "January", isso dependeria de quais índices existem na tabela. Se houver um índice na coluna em questão, o otimizador de consulta quase certamente usará esse índice para localizar as linhas relevantes em alguns acessos ao disco. Se não houver índice na coluna em questão, a consulta teria que fazer uma varredura completa da tabela na TabelaB, o que poderia acarretar milhões de acessos ao disco se houvesse linhas suficientes na TabelaB.
A questão se torna mais interessante é você perguntar sobre um select que une TableA e TableB. Você não perguntou sobre isso. nesse caso, você precisará da coluna StudentID na TabelaB, mesmo que não a declare como FK.
No que diz respeito a ter uma coluna como StudentID que funciona como uma chave estrangeira, mas não é declarada com uma restrição FK, geralmente é uma má ideia, pelos motivos descritos na resposta de joanolo.